ipvsadm-1.26/config_stream.c0000664000076400007640000000550311064475161016035 0ustar wensongwensong/* * Code to convert a stream input into a dynamic array * that can be parsed as argc and argv. * * Authors: Horms * * Released under the terms of the GNU GPL * * ChangeLog * Horms : scanf Glibc under Red Hat 7 does not appear * to return EOF when input ends. Fall through * code has been added to handle this case correctly */ #include "config_stream.h" /********************************************************************** * config_stream_read * Read in a config file and put elements in a dynamic array * pre: stream: stream to read configuration from * return: dynamic array whose elements are the space delimited * tokens read from the stream. Result is returned * once a newline is reached so multiple calls * will be required to read an entire stream. * Everything including and after a hash (#) on a line is * ignored **********************************************************************/ dynamic_array_t * config_stream_read(FILE * stream, const char *first_element) { char token[MAX_LINE_LENGTH]; char tail[2]; char format[MAX_LINE_LENGTH]; char format_whitespace[MAX_LINE_LENGTH]; int status; int ntoken; int comment = 0; char *s; int c; int flag; dynamic_array_t *a; if ((a = dynamic_array_create((size_t) 0)) == NULL) { perror("config_file_read: dynamic_array_create"); return (NULL); } /*insert a argv[0] into the dynamic array */ if ((a = dynamic_array_add_element(a, (first_element != NULL ? first_element : ""), DESTROY_STR, DUP_STR)) == NULL) { perror("config_file_read: dynamic_array_add_element"); return (NULL); } sprintf(format, "%%%d[^ \t\n\r]%%1[ \t\n\r]", MAX_LINE_LENGTH); sprintf(format_whitespace, "%%%d[ \t\r]%%1[\n]", MAX_LINE_LENGTH); ntoken = 0; while ((status = fscanf(stream, format, token, tail)) != EOF) { if (status == 0) { flag = 1; while (flag) { c = fgetc(stream); switch (c) { case EOF: dynamic_array_destroy(a, DESTROY_STR); return (NULL); case '\n': return (a); case '\t': case '\r': case ' ': break; default: ungetc(c, stream); flag = 0; } } continue; } if (!comment && strcmp(token, "ipvsadm")) { ntoken++; if ((a = dynamic_array_add_element(a, token, DESTROY_STR, DUP_STR)) == NULL) { perror("config_file_read: dynamic_array_add_element"); dynamic_array_destroy(a, DESTROY_STR); return (NULL); } } if ((s = strrchr(tail, '\n')) != NULL) { return (a); } if (!comment) { comment = (strchr((s != NULL ? s : tail), '#') == NULL) ? 0 : 1; } } if (ntoken == 0) { dynamic_array_destroy(a, DESTROY_STR); return (NULL); } return (a); } ipvsadm-1.26/config_stream.h0000664000076400007640000000064311064475161016042 0ustar wensongwensong/* * Code to convert a stream input into a dynamic array * that can be parsed as argc and argv. * * Authors: Horms * * Released under the terms of the GNU GPL */ #ifndef CONFIG_STREAM_FLIM #define CONFIG_STREAM_FLIM #include "dynamic_array.h" #define MAX_LINE_LENGTH 4096 dynamic_array_t *config_stream_read(FILE * stream, const char *first_element); #endif ipvsadm-1.26/contrib/0000775000076400007640000000000011064475161014506 5ustar wensongwensongipvsadm-1.26/contrib/popt-optional.diff0000664000076400007640000000143111064475161020144 0ustar wensongwensong--- 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; + } } } } ipvsadm-1.26/debian/0000775000076400007640000000000011064475161014270 5ustar wensongwensongipvsadm-1.26/debian/control0000664000076400007640000000050711064475161015675 0ustar wensongwensongSource: ipvsadm Section: net Priority: optional Maintainer: Horms Standards-Version: 3.1.1 Package: ipvsadm Architecture: any Depends: ${shlibs:Depends} Description: ipvsadm is a utility to administer the IP virtual server services offered by the Linux kernel augmented with the virtual server patch. ipvsadm-1.26/debian/files0000664000076400007640000000005211064475161015312 0ustar wensongwensongipvsadm_1.25-ipv6-1_i386.deb net optional ipvsadm-1.26/debian/ipvsadm.dirs0000664000076400007640000000000111064475161016605 0ustar wensongwensong ipvsadm-1.26/debian/ipvsadm.files0000664000076400007640000000013611064475161016757 0ustar wensongwensongsbin/ipvsadm sbin/ipvsadm-restore sbin/ipvsadm-save usr/man/man8/ipvsadm.8 etc/init.d/ipvsadm ipvsadm-1.26/debian/changelog0000664000076400007640000000166711064475161016154 0ustar wensongwensongipvsadm (1.25-nl-5) hardy; urgency=low * use strtoul to convert ip addresses from hex from Simon Horman -- Vince Busam Wed, 20 Aug 2008 10:34:58 -0700 ipvsadm (1.25-nl-4) unstable; urgency=low * Fixed sorting of IPv6 addresses -- Vince Busam Fri, 15 Aug 2008 13:15:06 -0700 ipvsadm (1.25-nl-2) hardy; urgency=low * Code cleanups -- Vince Busam Wed, 23 Jul 2008 13:17:46 -0700 ipvsadm (1.25-nl-1) hardy; urgency=low * Add support for experimental netlink interface -- Vince Busam Tue, 22 Jul 2008 15:50:38 -0700 ipvsadm (1.25-ipv6-1) nstable; urgency=low * Add IPv6 support -- "Vince Busam" Wed, 21 May 2008 15:12:42 +0200 ipvsadm (1.13-1) nstable; urgency=low * A release -- Horms Thu, 14 Dec 2000 17:00:00 -0800 Local variables: mode: debian-changelog End: eoch ipvsadm-1.26/debian/copyright0000664000076400007640000000352411064475161016227 0ustar wensongwensong-------------------------------------------------------------------------- ipvsadm - Version 1.14 - 11th January 2001 This is free software. See below for details. ipvsadm is a utility to administer the IP virtual server services offered by the Linux kernel with IP virtual server support. This version of ipvsadm requires IPVS module v0.0.5 for kernel 2.4 or later. Check out the Linux Virtual Server Project home page on the World Wide Web: http://www.LinuxVirtualServer.org/ or http://www.Linux-VS.org/ for the most recent information and original sources about ipvsadm. To make, make sure your Linux kernel is already patched with IPVS and "make menuconfig" or "make xconfig" to setup the right compiling options, see the README of the virtual server patch for detail, then simply type make in the source directory. Install to your liking. We suggest the following pathnames: /sbin/ipvsadm /usr/man/man8/ipvsadm.8 This will be done automatically when calling make install in the source directory. Wensong Zhang -------------------------------------------------------------------------- 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -------------------------------------------------------------------- ipvsadm-1.26/debian/rules0000664000076400007640000000204511064475161015346 0ustar wensongwensong#!/usr/bin/make -f # Sample debian/rules that uses debhelper. # GNU copyright 1997 to 1999 by Joey Hess. export DH_COMPAT=2 pwd:=$(shell pwd) cfg:= build: build-stamp build-stamp: dh_testdir #test -x autogen.sh && ./autogen.sh $(cfg) || ./configure $(cfg) $(MAKE) touch build-stamp clean: dh_testdir dh_testroot rm -f build-stamp -$(MAKE) distclean dh_clean install: build dh_testdir dh_testroot dh_clean -k dh_installdirs BUILD_ROOT=$(pwd)/debian/tmp make install [ ! -d $(pwd)/debian/tmp/etc/init.d/ ] && \ mkdir -p $(pwd)/debian/tmp/etc/init.d/ install -c -m 755 ipvsadm.sh $(pwd)/debian/tmp/etc/init.d/ipvsadm dh_movefiles --source=debian/tmp binary-indep: build install binary-arch: build install dh_testversion 2.0 dh_testdir dh_testroot dh_installdocs dh_installchangelogs dh_link dh_strip dh_compress dh_fixperms dh_suidregister dh_makeshlibs dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install ipvsadm-1.26/debian/ipvsadm.substvars0000664000076400007640000000007211064475161017710 0ustar wensongwensongshlibs:Depends=libpopt0 (>= 1.10), libnl1, libc6 (>= 2.4) ipvsadm-1.26/dynamic_array.c0000664000076400007640000002025211064475161016035 0ustar wensongwensong/* * Dynamic array, to store all your flims in Includes macros required * to create an array of strings but as the primitive type for the * array is void * providing your own duplicate_primitive and * destroy_primitive functions will allow you to use the dynamic_array * API to have a dynamic array containing any primitive * * Authors: Horms * * Released under the terms of the GNU GPL * */ #include "dynamic_array.h" /********************************************************************** * dynamic_array_create * Create a dynamic array * pre: block_size: blocking size to use. * DEFAULT_DYNAMIC_ARRAY_BLOCK_SIZE is used if block_size is 0 * Block size refers to how many elements are prealocated * each time the array is grown. * return: An empty dynamic array * NULL on error **********************************************************************/ dynamic_array_t * dynamic_array_create(size_t block_size) { dynamic_array_t *a; if ((a = (dynamic_array_t *) malloc(sizeof(dynamic_array_t))) == NULL) { return (NULL); } a->vector = NULL; a->count = 0; a->allocated_size = 0; a->block_size = block_size ? block_size : DEFAULT_DYNAMIC_ARRAY_BLOCK_SIZE; return (a); } /********************************************************************** * dynamic_array_destroy * Free an array an all the elements held within * pre: a: array to destroy * destroy_element: pointer to funtion to destroy array elements * Function should take an argument of a pointer * and free the memory allocated to the structure * pointed to. * post: array is freed and destroy_element is called for all elements * of the array. * Nothing if a is NULL **********************************************************************/ void dynamic_array_destroy(dynamic_array_t * a, void (*destroy_element) (void *)) { if (a == NULL) return; while (a->count-- > 0) { destroy_element(*(a->vector + a->count)); } if (a->allocated_size > 0) { free(a->vector); } } /********************************************************************** * dynamic_array_add_element * Add an element to a dynamic array * pre: a: dynamic array to add element to * e: element to add * destroy_element: pointer to a function to destroy an element * passed to dynamic_array_destroy on error * duplicate_element: pointer to a function to duplicate an * element should take a pointer to an element * to duplicate as the only element and return * a copy of the element Any memory allocation * required should be done by this function. * post: element in inserted in the first unused position in the array * array size is increased by a->block_size if there is * insufficient room in the array to add the element. * Nothing is done if e is NULL * return: a on success * NULL if a is NULL or an error occurs **********************************************************************/ dynamic_array_t * dynamic_array_add_element(dynamic_array_t * a, const void *e, void (*destroy_element) (void *s), void *(*duplicate_element) (const void *s)) { if (a == NULL) return (NULL); if (e == NULL) return (a); if (a->count == a->allocated_size) { a->allocated_size += a->block_size; if ( (a->vector = (void **) realloc(a->vector, a->allocated_size * sizeof(void *))) == NULL) { dynamic_array_destroy(a, destroy_element); return (NULL); } } if ((*(a->vector + a->count) = (void *) duplicate_element(e)) == NULL) { return (NULL); } a->count++; return (a); } /********************************************************************** * dynamic_array_display * Print the contents of a dynamic array to a string * pre: a: dynamic array to display * delimiter: character to place between elements of the array * display_element: pointer to a function to display an element * element_length: pointer to a function to return the * length of an element * post: If a is NULL or there are no elements in a then nothing is done * Else a character buffer is alocated and the contents * of each array element, separated by delimiter is placed * in the '\0' termintated buffer returned. It is up to the * user to free this buffer. * return: Allocated buffer as above * NULL on error, NULL a or empty a **********************************************************************/ char * dynamic_array_display(dynamic_array_t * a, char delimiter, void (*display_element) (char *, void *), size_t(*element_length) (void *)) { void **a_current; void **a_top; char *buffer; char *buffer_current; size_t nochar; size_t len = 0; if (a == NULL || a->count == 0) { return (NULL); } a_top = a->vector + a->count; nochar = a->count; for (a_current = a->vector; a_current < a_top; a_current++) { nochar += (len = element_length(*a_current)); if (!len) { nochar--; } } if ((buffer = (char *) malloc(nochar)) == NULL) { return (NULL); } buffer_current = buffer; for (a_current = a->vector; a_current < a_top; a_current++) { if ((len = element_length(*a_current))) { display_element(buffer_current, *a_current); buffer_current += element_length(*a_current); *buffer_current++ = delimiter; } } if (len) { buffer_current--; } *buffer_current = '\0'; return (buffer); } /********************************************************************** * dynamic_array_get_element * Get an element from an array * pre: a: array to retrieve element from * elementno: index element in array to retrieve * post: no change is made to a * return: element requested * NULL if element is beyond the number of elements in the arary **********************************************************************/ void * dynamic_array_get_element(dynamic_array_t * a, size_t elementno) { if (elementno > a->count) return (NULL); return (*((a->vector) + elementno)); } /********************************************************************** * dynamic_array_get_count * Get the number of elements in the array * pre: array to find the number of elements in * return: number of elements in the array * -1 if a is NULL **********************************************************************/ size_t dynamic_array_get_count(dynamic_array_t * a) { if (a == NULL) return (-1); return (a->count); } /********************************************************************** * dynamic_array_get_vector * Get the array contained in the dynamic array * pre: array to find the vector of * return: vector * NULL if a is NULL **********************************************************************/ void * dynamic_array_get_vector(dynamic_array_t * a) { if (a == NULL) return (NULL); return (a->vector); } /********************************************************************** * dynamic_array_split_str * Split a string into substrings on a delimiter * pre: str: string to split * delimiter: character to split string on * post: string is split. * Note: The string is modified. * return: dynamic array containing sub_strings * NULL on error * string being NULL is an error state **********************************************************************/ dynamic_array_t * dynamic_array_split_str(char *string, const char delimiter) { dynamic_array_t *a; char *sub_string; if (string == NULL) { return (NULL); } if ((a = dynamic_array_create(0)) == NULL) { return (NULL); } while ((sub_string = strchr(string, delimiter)) != NULL) { *sub_string = '\0'; if (dynamic_array_add_element(a, string, DESTROY_STR, DUP_STR) == NULL) { return (NULL); } string = sub_string + 1; } if (*string != '\0' && dynamic_array_add_element(a, string, DESTROY_STR, DUP_STR) == NULL) { return (NULL); } return (a); } ipvsadm-1.26/dynamic_array.h0000664000076400007640000001466711064475161016057 0ustar wensongwensong/* * Dynamic array, to store all your flims in Includes macros required * to create an array of strings but as the primitive type for the * array is void * providing your own duplicate_primitive and * destroy_primitive functions will allow you to use the dynamic_array * API to have a dynamic array containing any primitive * * Authors: Horms * * Released under the terms of the GNU GPL * */ #ifndef DYNAMIC_ARRAY_FLIM #define DYNAMIC_ARRAY_FLIM #include #include #include #include /* * Default blocking size for dynamic array * can be overriden when array is created */ #define DEFAULT_DYNAMIC_ARRAY_BLOCK_SIZE (size_t)7 /* #defines to destroy and dupilcate strings */ #define DESTROY_STR (void (*)(void *s))free #define DUP_STR (void *(*)(const void *s))strdup #define DISPLAY_STR (void (*)(char *d, void *s))strcpy #define LEN_STR (size_t (*)(void *s))strlen typedef struct { void **vector; size_t count; size_t allocated_size; size_t block_size; } dynamic_array_t; /********************************************************************** * dynamic_array_create * Create a dynamic array * pre: block_size: blocking size to use. * DEFAULT_DYNAMIC_ARRAY_BLOCK_SIZE is used if * block_size is 0 * Block size refers to how many elements are prealocated * each time the array is grown. * return: An empty dynamic array * NULL on error **********************************************************************/ extern dynamic_array_t *dynamic_array_create(size_t block_size); /********************************************************************** * dynamic_array_destroy * Free an array an all the elements held within * pre: a: array to destroy * destroy_element: pointer to funtion to destroy array elements * Function should take an argument of a pointer * and free the memory allocated to the structure * pointed to. * post: array is freed and destroy_element is called for all elements * of the array. * Nothing if a is NULL **********************************************************************/ void dynamic_array_destroy(dynamic_array_t * a, void (*destroy_element) (void *)); /********************************************************************** * dynamic_array_add_element * Add an element to a dynamic array * pre: a: dynamic array to add element to * e: element to add * destroy_element: pointer to a function to destroy an element * passed to dynamic_array_destroy on error * duplicate_element: pointer to a function to duplicate an * element should take a pointer to an element * to duplicate as the only element and return * a copy of the element Any memory allocation * required should be done by this function. * post: element in inserted in the first unused position in the array * array size is increased by a->block_size if there is * insufficient room in the array to add the element. * Nothing is done if e is NULL * return: a on success * NULL if a is NULL or an error occurs **********************************************************************/ dynamic_array_t *dynamic_array_add_element(dynamic_array_t * a, const void *e, void (*destroy_element) (void *s), void *(*duplicate_element) (const void *s)); /********************************************************************** * dynamic_array_display * Print the contents of a dynamic array to a string * pre: a: dynamic array to display * delimiter: character to place between elements of the array * display_element: pointer to a function to display an element * element_length: pointer to a function to return the * length of an element * post: If a is NULL or there are no elements in a then nothing is done * Else a character buffer is alocated and the contents * of each array element, separated by delimiter is placed * in the '\0' termintated buffer returned. It is up to the * user to free this buffer. * return: Allocated buffer as above * NULL on error, NULL a or empty a **********************************************************************/ char *dynamic_array_display(dynamic_array_t * a, char delimiter, void (*display_element) (char *, void *), size_t(*element_length) (void *) ); /********************************************************************** * dynamic_array_get_element * Get an element from an array * pre: a: array to retrieve element from * elementno: index element in array to retrieve * post: no change is made to a * return: element requested * NULL if element is beyond the number of elements in the arary **********************************************************************/ void *dynamic_array_get_element(dynamic_array_t * a, size_t elementno); /********************************************************************** * dynamic_array_get_count * Get the number of elements in the array * pre: array to find the number of elements in * return: number of elements in the array * -1 if a is NULL **********************************************************************/ size_t dynamic_array_get_count(dynamic_array_t * a); /********************************************************************** * dynamic_array_get_vector * Get the array contained in the dynamic array * pre: array to find the vector of * return: vector * NULL if a is NULL **********************************************************************/ void *dynamic_array_get_vector(dynamic_array_t * a); /********************************************************************** * dynamic_array_split_str * Split a string into substrings on a delimiter * pre: str: string to split * delimiter: character to split string on * post: string is split. * Note: The string is modified. * return: dynamic array containing sub_strings * NULL on error * string being NULL is an error state **********************************************************************/ dynamic_array_t *dynamic_array_split_str(char *string, const char delimiter); #endif ipvsadm-1.26/ipvsadm.80000664000076400007640000005722311523655501014611 0ustar wensongwensong.\" .\" ipvsadm(8) manual page .\" .\" $Id: ipvsadm.8 73 2010-10-07 12:59:40Z horms $ .\" .\" Authors: Mike Wangsmo .\" Wensong Zhang .\" .\" Changes: .\" Horms : Updated to reflect recent change of ipvsadm .\" : Style guidance taken from ipchains(8) .\" where appropriate. .\" Wensong Zhang : Added a short note about the defense strategies .\" Horms : Tidy up some of the description and the .\" grammar in the -f and sysctl sections .\" Wensong Zhang : --set option description taken from ipchains(8) .\" .\" 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. .\" .\" This program is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" along with this program; if not, write to the Free Software .\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. .\" .\" .TH IPVSADM 8 "5th July 2003" "LVS Administration" "Linux Administrator's Guide" .UC 4 .SH NAME ipvsadm \- Linux Virtual Server administration .SH SYNOPSIS .B ipvsadm -A|E -t|u|f \fIservice-address\fP [-s \fIscheduler\fP] .ti 15 .B [-p [\fItimeout\fP]] [-M \fInetmask\fP] .br .B ipvsadm -D -t|u|f \fIservice-address\fP .br .B ipvsadm -C .br .B ipvsadm -R .br .B ipvsadm -S [-n] .br .B ipvsadm -a|e -t|u|f \fIservice-address\fP -r \fIserver-address\fP .ti 15 .B [-g|i|m] [-w \fIweight\fP] [-x \fIupper\fP] [-y \fIlower\fP] .br .B ipvsadm -d -t|u|f \fIservice-address\fP -r \fIserver-address\fP .br .B ipvsadm -L|l [options] .br .B ipvsadm -Z [-t|u|f \fIservice-address\fP] .br .B ipvsadm --set \fItcp\fP \fItcpfin\fP \fIudp\fP .br .B ipvsadm --start-daemon \fIstate\fP [--mcast-interface \fIinterface\fP] .ti 15 .B [--syncid \fIsyncid\fP] .br .B ipvsadm --stop-daemon \fIstate\fP .br .B ipvsadm -h .SH DESCRIPTION \fBIpvsadm\fR(8) is used to set up, maintain or inspect the virtual server table in the Linux kernel. The Linux Virtual Server can be used to build scalable network services based on a cluster of two or more nodes. The active node of the cluster redirects service requests to a collection of server hosts that will actually perform the services. Supported features include two protocols (TCP and UDP), three packet-forwarding methods (NAT, tunneling, and direct routing), and eight load balancing algorithms (round robin, weighted round robin, least-connection, weighted least-connection, locality-based least-connection, locality-based least-connection with replication, destination-hashing, and source-hashing). .PP The command has two basic formats for execution: .TP .B ipvsadm \fICOMMAND\fP [\fIprotocol\fP] \fIservice-address\fP .ti 15 .B [\fIscheduling-method\fP] [\fIpersistence options\fP] .TP .B ipvsadm \fIcommand\fP [\fIprotocol\fP] \fIservice-address\fP .ti 15 .B \fIserver-address\fP [\fIpacket-forwarding-method\fP] .ti 15 .B [\fIweight options\fP] .PP The first format manipulates a virtual service and the algorithm for assigning service requests to real servers. Optionally, a persistent timeout and network mask for the granularity of a persistent service may be specified. The second format manipulates a real server that is associated with an existing virtual service. When specifying a real server, the packet-forwarding method and the weight of the real server, relative to other real servers for the virtual service, may be specified, otherwise defaults will be used. .SS COMMANDS \fBipvsadm\fR(8) recognises the commands described below. Upper-case commands maintain virtual services. Lower-case commands maintain real servers that are associated with a virtual service. .TP .B -A, --add-service Add a virtual service. A service address is uniquely defined by a triplet: IP address, port number, and protocol. Alternatively, a virtual service may be defined by a firewall-mark. .TP .B -E, --edit-service Edit a virtual service. .TP .B -D, --delete-service Delete a virtual service, along with any associated real servers. .TP .B -C, --clear Clear the virtual server table. .TP .B -R, --restore Restore Linux Virtual Server rules from stdin. Each line read from stdin will be treated as the command line options to a separate invocation of \fIipvsadm\fP. Lines read from stdin can optionally begin with "ipvsadm". This option is useful to avoid executing a large number or \fIipvsadm\fP commands when constructing an extensive routing table. .TP .B -S, --save Dump the Linux Virtual Server rules to stdout in a format that can be read by -R|--restore. .TP .B -a, --add-server Add a real server to a virtual service. .TP .B -e, --edit-server Edit a real server in a virtual service. .TP .B -d, --delete-server Remove a real server from a virtual service. .TP .B -L, -l, --list List the virtual server table if no argument is specified. If a \fIservice-address\fP is selected, list this service only. If the \fI-c\fP option is selected, then display the connection table. The exact output is affected by the other arguments given. .TP .B -Z, --zero Zero the packet, byte and rate counters in a service or all services. .TP .B --set \fItcp\fP \fItcpfin\fP \fIudp\fP Change the timeout values used for IPVS connections. This command always takes 3 parameters, representing the timeout values (in seconds) for TCP sessions, TCP sessions after receiving a FIN packet, and UDP packets, respectively. A timeout value 0 means that the current timeout value of the corresponding entry is preserved. .TP .B --start-daemon \fIstate\fP Start the connection synchronization daemon. The \fIstate\fP is to indicate that the daemon is started as \fImaster\fP or \fIbackup\fP. The connection synchronization daemon is implemented inside the Linux kernel. The master daemon running at the primary load balancer multicasts changes of connections periodically, and the backup daemon running at the backup load balancers receives multicast message and creates corresponding connections. Then, in case the primary load balancer fails, a backup load balancer will takeover, and it has state of almost all connections, so that almost all established connections can continue to access the service. .PP The sync daemon currently only supports IPv4 connections. .TP .B --stop-daemon Stop the connection synchronization daemon. .TP \fB-h, --help\fR Display a description of the command syntax. .SS PARAMETERS The commands above accept or require zero or more of the following parameters. .TP .B -t, --tcp-service \fIservice-address\fP Use TCP service. The \fIservice-address\fP is of the form \fIhost[:port]\fP. \fIHost\fP may be one of a plain IP address or a hostname. \fIPort\fP may be either a plain port number or the service name of port. The \fIPort\fP may be omitted, in which case zero will be used. A \fIPort\fP of zero is only valid if the service is persistent as the -p|--persistent option, in which case it is a wild-card port, that is connections will be accepted to any port. .TP .B -u, --udp-service \fIservice-address\fP Use UDP service. See the -t|--tcp-service for the description of the \fIservice-address\fP. .TP .B -f, --fwmark-service \fIinteger\fP Use a firewall-mark, an integer value greater than zero, to denote a virtual service instead of an address, port and protocol (UDP or TCP). The marking of packets with a firewall-mark is configured using the -m|--mark option to \fBiptables\fR(8). It can be used to build a virtual service associated with the same real servers, covering multiple IP address, port and protocol triplets. If IPv6 addresses are used, the -6 option must be used. .sp Using firewall-mark virtual services provides a convenient method of grouping together different IP addresses, ports and protocols into a single virtual service. This is useful for both simplifying configuration if a large number of virtual services are required and grouping persistence across what would otherwise be multiple virtual services. .TP .B -s, --scheduler \fIscheduling-method\fP \fIscheduling-method\fP Algorithm for allocating TCP connections and UDP datagrams to real servers. Scheduling algorithms are implemented as kernel modules. Ten are shipped with the Linux Virtual Server: .sp \fBrr\fR - Round Robin: distributes jobs equally amongst the available real servers. .sp \fBwrr\fR - Weighted Round Robin: assigns jobs to real servers proportionally to there real servers' weight. Servers with higher weights receive new jobs first and get more jobs than servers with lower weights. Servers with equal weights get an equal distribution of new jobs. .sp \fBlc\fR - Least-Connection: assigns more jobs to real servers with fewer active jobs. .sp \fBwlc\fR - Weighted Least-Connection: assigns more jobs to servers with fewer jobs and relative to the real servers' weight (Ci/Wi). This is the default. .sp \fBlblc\fR - Locality-Based Least-Connection: assigns jobs destined for the same IP address to the same server if the server is not overloaded and available; otherwise assign jobs to servers with fewer jobs, and keep it for future assignment. .sp \fBlblcr\fR - Locality-Based Least-Connection with Replication: assigns jobs destined for the same IP address to the least-connection node in the server set for the IP address. If all the node in the server set are over loaded, it picks up a node with fewer jobs in the cluster and adds it in the sever set for the target. If the server set has not been modified for the specified time, the most loaded node is removed from the server set, in order to avoid high degree of replication. .sp \fBdh\fR - Destination Hashing: assigns jobs to servers through looking up a statically assigned hash table by their destination IP addresses. .sp \fBsh\fR - Source Hashing: assigns jobs to servers through looking up a statically assigned hash table by their source IP addresses. .sp \fBsed\fR - Shortest Expected Delay: assigns an incoming job to the server with the shortest expected delay. The expected delay that the job will experience is (Ci + 1) / Ui if sent to the ith server, in which Ci is the number of jobs on the the ith server and Ui is the fixed service rate (weight) of the ith server. .sp \fBnq\fR - Never Queue: assigns an incoming job to an idle server if there is, instead of waiting for a fast one; if all the servers are busy, it adopts the Shortest Expected Delay policy to assign the job. .TP .B -p, --persistent [\fItimeout\fP] Specify that a virtual service is persistent. If this option is specified, multiple requests from a client are redirected to the same real server selected for the first request. Optionally, the \fItimeout\fP of persistent sessions may be specified given in seconds, otherwise the default of 300 seconds will be used. This option may be used in conjunction with protocols such as SSL or FTP where it is important that clients consistently connect with the same real server. .sp \fBNote:\fR If a virtual service is to handle FTP connections then persistence must be set for the virtual service if Direct Routing or Tunnelling is used as the forwarding mechanism. If Masquerading is used in conjunction with an FTP service than persistence is not necessary, but the ip_vs_ftp kernel module must be used. This module may be manually inserted into the kernel using insmod(8). .TP .B -M, --netmask \fInetmask\fP Specify the granularity with which clients are grouped for persistent virtual services. The source address of the request is masked with this netmask to direct all clients from a network to the same real server. The default is \fI255.255.255.255\fP, that is, the persistence granularity is per client host. Less specific netmasks may be used to resolve problems with non-persistent cache clusters on the client side. IPv6 netmasks should be specified as a prefix length between 1 and 128. The default prefix length is 128. .TP .B -r, --real-server \fIserver-address\fP Real server that an associated request for service may be assigned to. The \fIserver-address\fP is the \fIhost\fP address of a real server, and may plus \fIport\fP. \fIHost\fP can be either a plain IP address or a hostname. \fIPort\fP can be either a plain port number or the service name of port. In the case of the masquerading method, the host address is usually an RFC 1918 private IP address, and the port can be different from that of the associated service. With the tunneling and direct routing methods, \fIport\fP must be equal to that of the service address. For normal services, the port specified in the service address will be used if \fIport\fP is not specified. For fwmark services, \fIport\fP may be omitted, in which case the destination port on the real server will be the destination port of the request sent to the virtual service. .TP .B [packet-forwarding-method] .sp \fB-g, --gatewaying\fR Use gatewaying (direct routing). This is the default. .sp \fB-i, --ipip\fR Use ipip encapsulation (tunneling). .sp \fB-m, --masquerading\fR Use masquerading (network access translation, or NAT). .sp \fBNote:\fR Regardless of the packet-forwarding mechanism specified, real servers for addresses for which there are interfaces on the local node will be use the local forwarding method, then packets for the servers will be passed to upper layer on the local node. This cannot be specified by \fIipvsadm\fP, rather it set by the kernel as real servers are added or modified. .TP .B -w, --weight \fIweight\fP \fIWeight\fP is an integer specifying the capacity of a server relative to the others in the pool. The valid values of \fIweight\fP are 0 through to 65535. The default is 1. Quiescent servers are specified with a weight of zero. A quiescent server will receive no new jobs but still serve the existing jobs, for all scheduling algorithms distributed with the Linux Virtual Server. Setting a quiescent server may be useful if the server is overloaded or needs to be taken out of service for maintenance. .TP .B -x, --u-threshold \fIuthreshold\fP \fIuthreshold\fP is an integer specifying the upper connection threshold of a server. The valid values of \fIuthreshold\fP are 0 through to 65535. The default is 0, which means the upper connection threshold is not set. If \fIuthreshold\fP is set with other values, no new connections will be sent to the server when the number of its connections exceeds its upper connection threshold. .TP .B -y, --l-threshold \fIlthreshold\fP \fIlthreshold\fP is an integer specifying the lower connection threshold of a server. The valid values of \fIlthreshold\fP are 0 through to 65535. The default is 0, which means the lower connection threshold is not set. If \fIlthreshold\fP is set with other values, the server will receive new connections when the number of its connections drops below its lower connection threshold. If \fIlthreshold\fP is not set but \fIuthreshold\fP is set, the server will receive new connections when the number of its connections drops below three forth of its upper connection threshold. .TP .B --mcast-interface \fIinterface\fP Specify the multicast interface that the sync master daemon sends outgoing multicasts through, or the sync backup daemon listens to for multicasts. .TP .B --syncid \fIsyncid\fP Specify the \fIsyncid\fP that the sync master daemon fills in the SyncID header while sending multicast messages, or the sync backup daemon uses to filter out multicast messages not matched with the SyncID value. The valid values of \fIsyncid\fP are 0 through to 255. The default is 0, which means no filtering at all. .TP .B -c, --connection Connection output. The \fIlist\fP command with this option will list current IPVS connections. .TP .B --timeout Timeout output. The \fIlist\fP command with this option will display the timeout values (in seconds) for TCP sessions, TCP sessions after receiving a FIN packet, and UDP packets. .TP .B --daemon Daemon information output. The \fIlist\fP command with this option will display the daemon status and its multicast interface. .TP .B --stats Output of statistics information. The \fIlist\fP command with this option will display the statistics information of services and their servers. .TP .B --rate Output of rate information. The \fIlist\fP command with this option will display the rate information (such as connections/second, bytes/second and packets/second) of services and their servers. .TP .B --thresholds Output of thresholds information. The \fIlist\fP command with this option will display the upper/lower connection threshold information of each server in service listing. .TP .B --persistent-conn Output of persistent connection information. The \fIlist\fP command with this option will display the persistent connection counter information of each server in service listing. The persistent connection is used to forward the actual connections from the same client/network to the same server. .sp The \fIlist\fP command with the -c, --connection option and this option will include persistence engine data, if any is present, when listing connections. .TP .B --sort Sort the list of virtual services and real servers. The virtual service entries are sorted in ascending order by . The real server entries are sorted in ascending order by . (default) .TP .B --nosort Do not sort the list of virtual services and real servers. .TP .B -n, --numeric Numeric output. IP addresses and port numbers will be printed in numeric format rather than as as host names and services respectively, which is the default. .TP .B --exact Expand numbers. Display the exact value of the packet and byte counters, instead of only the rounded number in K's (multiples of 1000) M's (multiples of 1000K) or G's (multiples of 1000M). This option is only relevant for the -L command. .TP .B -6, --ipv6 Use with -f to signify fwmark rule uses IPv6 addresses. .TP .B -o, --ops One-packet scheduling. Used in conjunction with a UDP virtual service or a fwmark virtual service that handles only UDP packets. All connections are created such that they only schedule one packet. .SH EXAMPLE 1 - Simple Virtual Service The following commands configure a Linux Director to distribute incoming requests addressed to port 80 on 207.175.44.110 equally to port 80 on five real servers. The forwarding method used in this example is NAT, with each of the real servers being masqueraded by the Linux Director. .PP .nf ipvsadm -A -t 207.175.44.110:80 -s rr ipvsadm -a -t 207.175.44.110:80 -r 192.168.10.1:80 -m ipvsadm -a -t 207.175.44.110:80 -r 192.168.10.2:80 -m ipvsadm -a -t 207.175.44.110:80 -r 192.168.10.3:80 -m ipvsadm -a -t 207.175.44.110:80 -r 192.168.10.4:80 -m ipvsadm -a -t 207.175.44.110:80 -r 192.168.10.5:80 -m .fi .PP Alternatively, this could be achieved in a single ipvsadm command. .PP .nf echo " -A -t 207.175.44.110:80 -s rr -a -t 207.175.44.110:80 -r 192.168.10.1:80 -m -a -t 207.175.44.110:80 -r 192.168.10.2:80 -m -a -t 207.175.44.110:80 -r 192.168.10.3:80 -m -a -t 207.175.44.110:80 -r 192.168.10.4:80 -m -a -t 207.175.44.110:80 -r 192.168.10.5:80 -m " | ipvsadm -R .fi .PP As masquerading is used as the forwarding mechanism in this example, the default route of the real servers must be set to the linux director, which will need to be configured to forward and masquerade packets. This can be achieved using the following commands: .PP .nf echo "1" > /proc/sys/net/ipv4/ip_forward .fi .SH EXAMPLE 2 - Firewall-Mark Virtual Service The following commands configure a Linux Director to distribute incoming requests addressed to any port on 207.175.44.110 or 207.175.44.111 equally to the corresponding port on five real servers. As per the previous example, the forwarding method used in this example is NAT, with each of the real servers being masqueraded by the Linux Director. .PP .nf ipvsadm -A -f 1 -s rr ipvsadm -a -f 1 -r 192.168.10.1:0 -m ipvsadm -a -f 1 -r 192.168.10.2:0 -m ipvsadm -a -f 1 -r 192.168.10.3:0 -m ipvsadm -a -f 1 -r 192.168.10.4:0 -m ipvsadm -a -f 1 -r 192.168.10.5:0 -m .fi .PP As masquerading is used as the forwarding mechanism in this example, the default route of the real servers must be set to the linux director, which will need to be configured to forward and masquerade packets. The real server should also be configured to mark incoming packets addressed to any port on 207.175.44.110 and 207.175.44.111 with firewall-mark 1. If FTP traffic is to be handled by this virtual service, then the ip_vs_ftp kernel module needs to be inserted into the kernel. These operations can be achieved using the following commands: .PP .nf echo "1" > /proc/sys/net/ipv4/ip_forward modprobe ip_tables iptables -A PREROUTING -t mangle -d 207.175.44.110/31 -j MARK --set-mark 1 modprobe ip_vs_ftp .fi .SH IPv6 IPv6 addresses should be surrounded by square brackets ([ and ]). .PP .nf ipvsadm -A -t [2001:db8::80]:80 -s rr ipvsadm -a -t [2001:db8::80]:80 -r [2001:db8::a0a0]:80 -m .fi .PP fwmark IPv6 services require the -6 option. .SH NOTES The Linux Virtual Server implements three defense strategies against some types of denial of service (DoS) attacks. The Linux Director creates an entry for each connection in order to keep its state, and each entry occupies 128 bytes effective memory. LVS's vulnerability to a DoS attack lies in the potential to increase the number entries as much as possible until the linux director runs out of memory. The three defense strategies against the attack are: Randomly drop some entries in the table. Drop 1/rate packets before forwarding them. And use secure tcp state transition table and short timeouts. The strategies are controlled by sysctl variables and corresponding entries in the /proc filesystem: .sp /proc/sys/net/ipv4/vs/drop_entry /proc/sys/net/ipv4/vs/drop_packet /proc/sys/net/ipv4/vs/secure_tcp .PP Valid values for each variable are 0 through to 3. The default value is 0, which disables the respective defense strategy. 1 and 2 are automatic modes - when there is no enough available memory, the respective strategy will be enabled and the variable is automatically set to 2, otherwise the strategy is disabled and the variable is set to 1. A value of 3 denotes that the respective strategy is always enabled. The available memory threshold and secure TCP timeouts can be tuned using the sysctl variables and corresponding entries in the /proc filesystem: .sp /proc/sys/net/ipv4/vs/amemthresh /proc/sys/net/ipv4/vs/timeout_* .SH FILES .I /proc/net/ip_vs .br .I /proc/net/ip_vs_app .br .I /proc/net/ip_vs_conn .br .I /proc/net/ip_vs_stats .br .I /proc/sys/net/ipv4/vs/am_droprate .br .I /proc/sys/net/ipv4/vs/amemthresh .br .I /proc/sys/net/ipv4/vs/drop_entry .br .I /proc/sys/net/ipv4/vs/drop_packet .br .I /proc/sys/net/ipv4/vs/secure_tcp .br .I /proc/sys/net/ipv4/vs/timeout_close .br .I /proc/sys/net/ipv4/vs/timeout_closewait .br .I /proc/sys/net/ipv4/vs/timeout_established .br .I /proc/sys/net/ipv4/vs/timeout_finwait .br .I /proc/sys/net/ipv4/vs/timeout_icmp .br .I /proc/sys/net/ipv4/vs/timeout_lastack .br .I /proc/sys/net/ipv4/vs/timeout_listen .br .I /proc/sys/net/ipv4/vs/timeout_synack .br .I /proc/sys/net/ipv4/vs/timeout_synrecv .br .I /proc/sys/net/ipv4/vs/timeout_synsent .br .I /proc/sys/net/ipv4/vs/timeout_timewait .br .I /proc/sys/net/ipv4/vs/timeout_udp .SH SEE ALSO The LVS web site (http://www.linuxvirtualserver.org/) for more documentation about LVS. .PP \fBipvsadm-save\fP(8), \fBipvsadm-restore\fP(8), \fBiptables\fP(8), .br \fBinsmod\fP(8), \fBmodprobe\fP(8) .SH AUTHORS .nf ipvsadm - Wensong Zhang Peter Kese man page - Mike Wangsmo Wensong Zhang Horms .fi ipvsadm-1.26/ipvsadm.c0000664000076400007640000014256511523655501014670 0ustar wensongwensong/* * ipvsadm - IP Virtual Server ADMinistration program * for IPVS NetFilter Module in kernel 2.4 * * Version: $Id: ipvsadm.c 73 2010-10-07 12:59:40Z horms $ * * Authors: Wensong Zhang * Peter Kese * * This program is based on ippfvsadm. * * Changes: * Wensong Zhang : added the editting service & destination support * Wensong Zhang : added the feature to specify persistent port * Jacob Rief : found the bug that masquerading dest of * different vport and dport cannot be deleted. * Wensong Zhang : fixed it and changed some cosmetic things * Wensong Zhang : added the timeout setting for persistent service * Wensong Zhang : added specifying the dest weight zero * Wensong Zhang : fixed the -E and -e options * Wensong Zhang : added the long options * Wensong Zhang : added the hostname and portname input * Wensong Zhang : added the hostname and portname output * Lars Marowsky-Brée : added persistence granularity support * Julian Anastasov : fixed the (null) print for unknown services * Wensong Zhang : added the port_to_anyname function * Horms : added option to read commands from stdin * Horms : modified usage function so it prints to * : stdout if an exit value of 0 is used and * : stdout otherwise. Program is then terminated * : with the supplied exit value. * Horms : updated manpage and usage funtion so * : the reflect the options available * Wensong Zhang : added option to write rules to stdout * Horms : added ability to specify a fwmark * : instead of a server and port for * : a virtual service * Horms : tightened up checking of services * : in parse_service * Horms : ensure that a -r is passed when needed * Wensong Zhang : fixed the output of fwmark rules * Horms : added kernel version verification * Horms : Specifying command and option options * (e.g. -Ln or -At) in one short option * with popt problem fixed. * Wensong Zhang : split the process_options and make * two versions of parse_options. * Horms : attempting to save or restore when * compiled against getopt_long now results * in an informative error message rather * than the usage information * Horms : added -v option * Wensong Zhang : rewrite most code of parsing options and * processing options. * Alexandre Cassen : added ipvs_syncd SyncdID support to filter * incoming sync messages. * Guy Waugh & Ratz : added --exact option and spelling cleanup * vbusam@google.com : added IPv6 support * * * ippfvsadm - Port Fowarding & Virtual Server ADMinistration program * * Copyright (c) 1998 Wensong Zhang * All rights reserved. * * Author: Wensong Zhang * * This ippfvsadm is derived from Steven Clarke's ipportfw program. * * portfw - Port Forwarding Table Editing v1.1 * * Copyright (c) 1997 Steven Clarke * All rights reserved. * * Author: Steven Clarke * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #undef __KERNEL__ /* Makefile lazyness ;) */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* For waitpid */ #include #include #include #include #include #include "popt.h" #define IPVS_OPTION_PROCESSING "popt" #include "config_stream.h" #include "libipvs/libipvs.h" #define IPVSADM_VERSION_NO "v" VERSION #define IPVSADM_VERSION_DATE "2008/5/15" #define IPVSADM_VERSION IPVSADM_VERSION_NO " " IPVSADM_VERSION_DATE #define MAX_TIMEOUT (86400*31) /* 31 days */ #define CMD_NONE 0 #define CMD_ADD (CMD_NONE+1) #define CMD_EDIT (CMD_NONE+2) #define CMD_DEL (CMD_NONE+3) #define CMD_FLUSH (CMD_NONE+4) #define CMD_LIST (CMD_NONE+5) #define CMD_ADDDEST (CMD_NONE+6) #define CMD_DELDEST (CMD_NONE+7) #define CMD_EDITDEST (CMD_NONE+8) #define CMD_TIMEOUT (CMD_NONE+9) #define CMD_STARTDAEMON (CMD_NONE+10) #define CMD_STOPDAEMON (CMD_NONE+11) #define CMD_RESTORE (CMD_NONE+12) #define CMD_SAVE (CMD_NONE+13) #define CMD_ZERO (CMD_NONE+14) #define CMD_MAX CMD_ZERO #define NUMBER_OF_CMD (CMD_MAX - CMD_NONE) static const char* cmdnames[] = { "add-service", "edit-service", "delete-service", "flush", "list", "add-server", "delete-server", "edit-server", "set", "start-daemon", "stop-daemon", "restore", "save", "zero", }; #define OPT_NONE 0x000000 #define OPT_NUMERIC 0x000001 #define OPT_CONNECTION 0x000002 #define OPT_SERVICE 0x000004 #define OPT_SCHEDULER 0x000008 #define OPT_PERSISTENT 0x000010 #define OPT_NETMASK 0x000020 #define OPT_SERVER 0x000040 #define OPT_FORWARD 0x000080 #define OPT_WEIGHT 0x000100 #define OPT_UTHRESHOLD 0x000200 #define OPT_LTHRESHOLD 0x000400 #define OPT_MCAST 0x000800 #define OPT_TIMEOUT 0x001000 #define OPT_DAEMON 0x002000 #define OPT_STATS 0x004000 #define OPT_RATE 0x008000 #define OPT_THRESHOLDS 0x010000 #define OPT_PERSISTENTCONN 0x020000 #define OPT_NOSORT 0x040000 #define OPT_SYNCID 0x080000 #define OPT_EXACT 0x100000 #define OPT_ONEPACKET 0x200000 #define OPT_PERSISTENCE_ENGINE 0x400000 #define NUMBER_OF_OPT 23 static const char* optnames[] = { "numeric", "connection", "service-address", "scheduler", "pe", "persistent", "netmask", "real-server", "forwarding-method", "weight", "u-threshold", "l-threshold", "mcast-interface", "timeout", "daemon", "stats", "rate", "thresholds", "persistent-conn", "nosort", "syncid", "exact", "ops", }; /* * Table of legal combinations of commands and options. * Key: * '+' compulsory * 'x' illegal * '1' exclusive (only one '1' option can be supplied) * ' ' optional */ static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = { /* -n -c svc -s -p -M -r fwd -w -x -y -mc tot dmn -st -rt thr -pc srt sid -ex ops */ /*ADD*/ {'x', 'x', '+', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' '}, /*EDIT*/ {'x', 'x', '+', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' '}, /*DEL*/ {'x', 'x', '+', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, /*FLUSH*/ {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, /*LIST*/ {' ', '1', '1', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', '1', '1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x'}, /*ADDSRV*/ {'x', 'x', '+', 'x', 'x', 'x', '+', ' ', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, /*DELSRV*/ {'x', 'x', '+', 'x', 'x', 'x', '+', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, /*EDITSRV*/ {'x', 'x', '+', 'x', 'x', 'x', '+', ' ', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, /*TIMEOUT*/ {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, /*STARTD*/ {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' ', 'x', 'x'}, /*STOPD*/ {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' ', 'x', 'x'}, /*RESTORE*/ {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, /*SAVE*/ {' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, /*ZERO*/ {'x', 'x', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, }; /* printing format flags */ #define FMT_NONE 0x0000 #define FMT_NUMERIC 0x0001 #define FMT_RULE 0x0002 #define FMT_STATS 0x0004 #define FMT_RATE 0x0008 #define FMT_THRESHOLDS 0x0010 #define FMT_PERSISTENTCONN 0x0020 #define FMT_NOSORT 0x0040 #define FMT_EXACT 0x0080 #define SERVICE_NONE 0x0000 #define SERVICE_ADDR 0x0001 #define SERVICE_PORT 0x0002 /* default scheduler */ #define DEF_SCHED "wlc" /* default multicast interface name */ #define DEF_MCAST_IFN "eth0" #define CONN_PROC_FILE "/proc/net/ip_vs_conn" struct ipvs_command_entry { int cmd; ipvs_service_t svc; ipvs_dest_t dest; ipvs_timeout_t timeout; ipvs_daemon_t daemon; }; /* Use values outside ASCII range so that if an option has * a short name it can be used as the tag */ enum { TAG_SET = 128, TAG_START_DAEMON, TAG_STOP_DAEMON , TAG_MCAST_INTERFACE, TAG_TIMEOUT, TAG_DAEMON, TAG_STATS, TAG_RATE, TAG_THRESHOLDS, TAG_PERSISTENTCONN, TAG_SORT, TAG_NO_SORT, TAG_PERSISTENCE_ENGINE, }; /* various parsing helpers & parsing functions */ static int str_is_digit(const char *str); static int string_to_number(const char *s, int min, int max); static int host_to_addr(const char *name, struct in_addr *addr); static char * addr_to_host(int af, const void *addr); static char * addr_to_anyname(int af, const void *addr); static int service_to_port(const char *name, unsigned short proto); static char * port_to_service(unsigned short port, unsigned short proto); static char * port_to_anyname(unsigned short port, unsigned short proto); static char * addrport_to_anyname(int af, const void *addr, unsigned short port, unsigned short proto, unsigned int format); static int parse_service(char *buf, ipvs_service_t *svc); static int parse_netmask(char *buf, u_int32_t *addr); static int parse_timeout(char *buf, int min, int max); static unsigned int parse_fwmark(char *buf); /* check the options based on the commands_v_options table */ static void generic_opt_check(int command, int options); static void set_command(int *cmd, const int newcmd); static void set_option(unsigned int *options, unsigned int option); static void tryhelp_exit(const char *program, const int exit_status); static void usage_exit(const char *program, const int exit_status); static void version_exit(int exit_status); static void version(FILE *stream); static void fail(int err, char *msg, ...); /* various listing functions */ static void list_conn(unsigned int format); static void list_service(ipvs_service_t *svc, unsigned int format); static void list_all(unsigned int format); static void list_timeout(void); static void list_daemon(void); static int modprobe_ipvs(void); static void check_ipvs_version(void); static int process_options(int argc, char **argv, int reading_stdin); int main(int argc, char **argv) { int result; if (ipvs_init()) { /* try to insmod the ip_vs module if ipvs_init failed */ if (modprobe_ipvs() || ipvs_init()) fail(2, "Can't initialize ipvs: %s\n" "Are you sure that IP Virtual Server is " "built in the kernel or as module?", ipvs_strerror(errno)); } /* warn the user if the IPVS version is out of date */ check_ipvs_version(); /* list the table if there is no other arguement */ if (argc == 1){ list_all(FMT_NONE); ipvs_close(); return 0; } /* process command line arguments */ result = process_options(argc, argv, 0); ipvs_close(); return result; } static int parse_options(int argc, char **argv, struct ipvs_command_entry *ce, unsigned int *options, unsigned int *format) { int c, parse; poptContext context; char *optarg=NULL; struct poptOption options_table[] = { { "add-service", 'A', POPT_ARG_NONE, NULL, 'A', NULL, NULL }, { "edit-service", 'E', POPT_ARG_NONE, NULL, 'E', NULL, NULL }, { "delete-service", 'D', POPT_ARG_NONE, NULL, 'D', NULL, NULL }, { "clear", 'C', POPT_ARG_NONE, NULL, 'C', NULL, NULL }, { "list", 'L', POPT_ARG_NONE, NULL, 'L', NULL, NULL }, { "list", 'l', POPT_ARG_NONE, NULL, 'l', NULL, NULL }, { "zero", 'Z', POPT_ARG_NONE, NULL, 'Z', NULL, NULL }, { "add-server", 'a', POPT_ARG_NONE, NULL, 'a', NULL, NULL }, { "edit-server", 'e', POPT_ARG_NONE, NULL, 'e', NULL, NULL }, { "delete-server", 'd', POPT_ARG_NONE, NULL, 'd', NULL, NULL }, { "set", '\0', POPT_ARG_NONE, NULL, TAG_SET, NULL, NULL }, { "help", 'h', POPT_ARG_NONE, NULL, 'h', NULL, NULL }, { "version", 'v', POPT_ARG_NONE, NULL, 'v', NULL, NULL }, { "restore", 'R', POPT_ARG_NONE, NULL, 'R', NULL, NULL }, { "save", 'S', POPT_ARG_NONE, NULL, 'S', NULL, NULL }, { "start-daemon", '\0', POPT_ARG_STRING, &optarg, TAG_START_DAEMON, NULL, NULL }, { "stop-daemon", '\0', POPT_ARG_STRING, &optarg, TAG_STOP_DAEMON, NULL, NULL }, { "tcp-service", 't', POPT_ARG_STRING, &optarg, 't', NULL, NULL }, { "udp-service", 'u', POPT_ARG_STRING, &optarg, 'u', NULL, NULL }, { "fwmark-service", 'f', POPT_ARG_STRING, &optarg, 'f', NULL, NULL }, { "scheduler", 's', POPT_ARG_STRING, &optarg, 's', NULL, NULL }, { "persistent", 'p', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &optarg, 'p', NULL, NULL }, { "netmask", 'M', POPT_ARG_STRING, &optarg, 'M', NULL, NULL }, { "real-server", 'r', POPT_ARG_STRING, &optarg, 'r', NULL, NULL }, { "masquerading", 'm', POPT_ARG_NONE, NULL, 'm', NULL, NULL }, { "ipip", 'i', POPT_ARG_NONE, NULL, 'i', NULL, NULL }, { "gatewaying", 'g', POPT_ARG_NONE, NULL, 'g', NULL, NULL }, { "weight", 'w', POPT_ARG_STRING, &optarg, 'w', NULL, NULL }, { "u-threshold", 'x', POPT_ARG_STRING, &optarg, 'x', NULL, NULL }, { "l-threshold", 'y', POPT_ARG_STRING, &optarg, 'y', NULL, NULL }, { "numeric", 'n', POPT_ARG_NONE, NULL, 'n', NULL, NULL }, { "connection", 'c', POPT_ARG_NONE, NULL, 'c', NULL, NULL }, { "mcast-interface", '\0', POPT_ARG_STRING, &optarg, TAG_MCAST_INTERFACE, NULL, NULL }, { "syncid", '\0', POPT_ARG_STRING, &optarg, 'I', NULL, NULL }, { "timeout", '\0', POPT_ARG_NONE, NULL, TAG_TIMEOUT, NULL, NULL }, { "daemon", '\0', POPT_ARG_NONE, NULL, TAG_DAEMON, NULL, NULL }, { "stats", '\0', POPT_ARG_NONE, NULL, TAG_STATS, NULL, NULL }, { "rate", '\0', POPT_ARG_NONE, NULL, TAG_RATE, NULL, NULL }, { "thresholds", '\0', POPT_ARG_NONE, NULL, TAG_THRESHOLDS, NULL, NULL }, { "persistent-conn", '\0', POPT_ARG_NONE, NULL, TAG_PERSISTENTCONN, NULL, NULL }, { "nosort", '\0', POPT_ARG_NONE, NULL, TAG_NO_SORT, NULL, NULL }, { "sort", '\0', POPT_ARG_NONE, NULL, TAG_SORT, NULL, NULL }, { "exact", 'X', POPT_ARG_NONE, NULL, 'X', NULL, NULL }, { "ipv6", '6', POPT_ARG_NONE, NULL, '6', NULL, NULL }, { "ops", 'o', POPT_ARG_NONE, NULL, 'o', NULL, NULL }, { "pe", '\0', POPT_ARG_STRING, &optarg, TAG_PERSISTENCE_ENGINE, NULL, NULL }, { NULL, 0, 0, NULL, 0, NULL, NULL } }; context = poptGetContext("ipvsadm", argc, (const char **)argv, options_table, 0); if ((c = poptGetNextOpt(context)) < 0) tryhelp_exit(argv[0], -1); switch (c) { case 'A': set_command(&ce->cmd, CMD_ADD); break; case 'E': set_command(&ce->cmd, CMD_EDIT); break; case 'D': set_command(&ce->cmd, CMD_DEL); break; case 'a': set_command(&ce->cmd, CMD_ADDDEST); break; case 'e': set_command(&ce->cmd, CMD_EDITDEST); break; case 'd': set_command(&ce->cmd, CMD_DELDEST); break; case 'C': set_command(&ce->cmd, CMD_FLUSH); break; case 'L': case 'l': set_command(&ce->cmd, CMD_LIST); break; case 'Z': set_command(&ce->cmd, CMD_ZERO); break; case TAG_SET: set_command(&ce->cmd, CMD_TIMEOUT); break; case 'R': set_command(&ce->cmd, CMD_RESTORE); break; case 'S': set_command(&ce->cmd, CMD_SAVE); break; case TAG_START_DAEMON: set_command(&ce->cmd, CMD_STARTDAEMON); if (!strcmp(optarg, "master")) ce->daemon.state = IP_VS_STATE_MASTER; else if (!strcmp(optarg, "backup")) ce->daemon.state = IP_VS_STATE_BACKUP; else fail(2, "illegal start-daemon parameter specified"); break; case TAG_STOP_DAEMON: set_command(&ce->cmd, CMD_STOPDAEMON); if (!strcmp(optarg, "master")) ce->daemon.state = IP_VS_STATE_MASTER; else if (!strcmp(optarg, "backup")) ce->daemon.state = IP_VS_STATE_BACKUP; else fail(2, "illegal start_daemon specified"); break; case 'h': usage_exit(argv[0], 0); break; case 'v': version_exit(0); break; default: tryhelp_exit(argv[0], -1); } while ((c=poptGetNextOpt(context)) >= 0){ switch (c) { case 't': case 'u': set_option(options, OPT_SERVICE); ce->svc.protocol = (c=='t' ? IPPROTO_TCP : IPPROTO_UDP); parse = parse_service(optarg, &ce->svc); if (!(parse & SERVICE_ADDR)) fail(2, "illegal virtual server " "address[:port] specified"); break; case 'f': set_option(options, OPT_SERVICE); /* * Set protocol to a sane values, even * though it is not used */ ce->svc.af = AF_INET; ce->svc.protocol = IPPROTO_TCP; ce->svc.fwmark = parse_fwmark(optarg); break; case 's': set_option(options, OPT_SCHEDULER); strncpy(ce->svc.sched_name, optarg, IP_VS_SCHEDNAME_MAXLEN); break; case 'p': set_option(options, OPT_PERSISTENT); ce->svc.flags |= IP_VS_SVC_F_PERSISTENT; ce->svc.timeout = parse_timeout(optarg, 1, MAX_TIMEOUT); break; case 'M': set_option(options, OPT_NETMASK); if (ce->svc.af != AF_INET6) { parse = parse_netmask(optarg, &ce->svc.netmask); if (parse != 1) fail(2, "illegal virtual server " "persistent mask specified"); } else { ce->svc.netmask = atoi(optarg); if ((ce->svc.netmask < 1) || (ce->svc.netmask > 128)) fail(2, "illegal ipv6 netmask specified"); } break; case 'r': set_option(options, OPT_SERVER); ipvs_service_t t_dest = ce->svc; parse = parse_service(optarg, &t_dest); ce->dest.af = t_dest.af; ce->dest.addr = t_dest.addr; ce->dest.port = t_dest.port; if (!(parse & SERVICE_ADDR)) fail(2, "illegal real server " "address[:port] specified"); /* copy vport to dport if not specified */ if (parse == 1) ce->dest.port = ce->svc.port; break; case 'i': set_option(options, OPT_FORWARD); ce->dest.conn_flags = IP_VS_CONN_F_TUNNEL; break; case 'g': set_option(options, OPT_FORWARD); ce->dest.conn_flags = IP_VS_CONN_F_DROUTE; break; case 'm': set_option(options, OPT_FORWARD); ce->dest.conn_flags = IP_VS_CONN_F_MASQ; break; case 'w': set_option(options, OPT_WEIGHT); if ((ce->dest.weight = string_to_number(optarg, 0, 65535)) == -1) fail(2, "illegal weight specified"); break; case 'x': set_option(options, OPT_UTHRESHOLD); if ((ce->dest.u_threshold = string_to_number(optarg, 0, INT_MAX)) == -1) fail(2, "illegal u_threshold specified"); break; case 'y': set_option(options, OPT_LTHRESHOLD); if ((ce->dest.l_threshold = string_to_number(optarg, 0, INT_MAX)) == -1) fail(2, "illegal l_threshold specified"); break; case 'c': set_option(options, OPT_CONNECTION); break; case 'n': set_option(options, OPT_NUMERIC); *format |= FMT_NUMERIC; break; case TAG_MCAST_INTERFACE: set_option(options, OPT_MCAST); strncpy(ce->daemon.mcast_ifn, optarg, IP_VS_IFNAME_MAXLEN); break; case 'I': set_option(options, OPT_SYNCID); if ((ce->daemon.syncid = string_to_number(optarg, 0, 255)) == -1) fail(2, "illegal syncid specified"); break; case TAG_TIMEOUT: set_option(options, OPT_TIMEOUT); break; case TAG_DAEMON: set_option(options, OPT_DAEMON); break; case TAG_STATS: set_option(options, OPT_STATS); *format |= FMT_STATS; break; case TAG_RATE: set_option(options, OPT_RATE); *format |= FMT_RATE; break; case TAG_THRESHOLDS: set_option(options, OPT_THRESHOLDS); *format |= FMT_THRESHOLDS; break; case TAG_PERSISTENTCONN: set_option(options, OPT_PERSISTENTCONN); *format |= FMT_PERSISTENTCONN; break; case TAG_NO_SORT: set_option(options, OPT_NOSORT ); *format |= FMT_NOSORT; break; case TAG_SORT: /* Sort is the default, this is a no-op for compatibility */ break; case 'X': set_option(options, OPT_EXACT); *format |= FMT_EXACT; break; case '6': if (ce->svc.fwmark) { ce->svc.af = AF_INET6; ce->svc.netmask = 128; } else { fail(2, "-6 used before -f\n"); } break; case 'o': set_option(options, OPT_ONEPACKET); ce->svc.flags |= IP_VS_SVC_F_ONEPACKET; break; case TAG_PERSISTENCE_ENGINE: set_option(options, OPT_PERSISTENCE_ENGINE); strncpy(ce->svc.pe_name, optarg, IP_VS_PENAME_MAXLEN); break; default: fail(2, "invalid option `%s'", poptBadOption(context, POPT_BADOPTION_NOALIAS)); } } if (c < -1) { /* an error occurred during option processing */ fprintf(stderr, "%s: %s\n", poptBadOption(context, POPT_BADOPTION_NOALIAS), poptStrerror(c)); poptFreeContext(context); return -1; } if (ce->cmd == CMD_TIMEOUT) { char *optarg1, *optarg2; if ((optarg=(char *)poptGetArg(context)) && (optarg1=(char *)poptGetArg(context)) && (optarg2=(char *)poptGetArg(context))) { ce->timeout.tcp_timeout = parse_timeout(optarg, 0, MAX_TIMEOUT); ce->timeout.tcp_fin_timeout = parse_timeout(optarg1, 0, MAX_TIMEOUT); ce->timeout.udp_timeout = parse_timeout(optarg2, 0, MAX_TIMEOUT); } else fail(2, "--set option requires 3 timeout values"); } if ((optarg=(char *)poptGetArg(context))) fail(2, "unexpected argument %s", optarg); poptFreeContext(context); return 0; } static int restore_table(int argc, char **argv, int reading_stdin) { int result = 0; dynamic_array_t *a; /* avoid infinite loop */ if (reading_stdin != 0) tryhelp_exit(argv[0], -1); while ((a = config_stream_read(stdin, argv[0])) != NULL) { int i; if ((i = (int)dynamic_array_get_count(a)) > 1) { char **strv = dynamic_array_get_vector(a); result = process_options(i, strv, 1); } dynamic_array_destroy(a, DESTROY_STR); } return result; } static int process_options(int argc, char **argv, int reading_stdin) { struct ipvs_command_entry ce; unsigned int options = OPT_NONE; unsigned int format = FMT_NONE; int result = 0; memset(&ce, 0, sizeof(struct ipvs_command_entry)); ce.cmd = CMD_NONE; /* Set the default weight 1 */ ce.dest.weight = 1; /* Set direct routing as default forwarding method */ ce.dest.conn_flags = IP_VS_CONN_F_DROUTE; /* Set the default persistent granularity to /32 mask */ ce.svc.netmask = ((u_int32_t) 0xffffffff); if (parse_options(argc, argv, &ce, &options, &format)) return -1; generic_opt_check(ce.cmd, options); if (ce.cmd == CMD_ADD || ce.cmd == CMD_EDIT) { /* Make sure that port zero service is persistent */ if (!ce.svc.fwmark && !ce.svc.port && !(ce.svc.flags & IP_VS_SVC_F_PERSISTENT)) fail(2, "Zero port specified " "for non-persistent service"); if (ce.svc.flags & IP_VS_SVC_F_ONEPACKET && !ce.svc.fwmark && ce.svc.protocol != IPPROTO_UDP) fail(2, "One-Packet Scheduling is only " "for UDP virtual services"); /* Set the default scheduling algorithm if not specified */ if (strlen(ce.svc.sched_name) == 0) strcpy(ce.svc.sched_name, DEF_SCHED); } if (ce.cmd == CMD_STARTDAEMON && strlen(ce.daemon.mcast_ifn) == 0) strcpy(ce.daemon.mcast_ifn, DEF_MCAST_IFN); if (ce.cmd == CMD_ADDDEST || ce.cmd == CMD_EDITDEST) { /* * The destination port must be equal to the service port * if the IP_VS_CONN_F_TUNNEL or IP_VS_CONN_F_DROUTE is set. * Don't worry about this if fwmark is used. */ if (!ce.svc.fwmark && (ce.dest.conn_flags == IP_VS_CONN_F_TUNNEL || ce.dest.conn_flags == IP_VS_CONN_F_DROUTE)) ce.dest.port = ce.svc.port; } switch (ce.cmd) { case CMD_LIST: if ((options & (OPT_CONNECTION|OPT_TIMEOUT|OPT_DAEMON) && options & (OPT_STATS|OPT_RATE|OPT_THRESHOLDS)) || (options & (OPT_TIMEOUT|OPT_DAEMON) && options & OPT_PERSISTENTCONN)) fail(2, "options conflicts in the list command"); if (options & OPT_CONNECTION) list_conn(format); else if (options & OPT_SERVICE) list_service(&ce.svc, format); else if (options & OPT_TIMEOUT) list_timeout(); else if (options & OPT_DAEMON) list_daemon(); else list_all(format); return 0; case CMD_RESTORE: return restore_table(argc, argv, reading_stdin); case CMD_SAVE: format |= FMT_RULE; list_all(format); return 0; case CMD_FLUSH: result = ipvs_flush(); break; case CMD_ADD: result = ipvs_add_service(&ce.svc); break; case CMD_EDIT: result = ipvs_update_service(&ce.svc); break; case CMD_DEL: result = ipvs_del_service(&ce.svc); break; case CMD_ZERO: result = ipvs_zero_service(&ce.svc); break; case CMD_ADDDEST: result = ipvs_add_dest(&ce.svc, &ce.dest); break; case CMD_EDITDEST: result = ipvs_update_dest(&ce.svc, &ce.dest); break; case CMD_DELDEST: result = ipvs_del_dest(&ce.svc, &ce.dest); break; case CMD_TIMEOUT: result = ipvs_set_timeout(&ce.timeout); break; case CMD_STARTDAEMON: result = ipvs_start_daemon(&ce.daemon); break; case CMD_STOPDAEMON: result = ipvs_stop_daemon(&ce.daemon); } if (result) fprintf(stderr, "%s\n", ipvs_strerror(errno)); return result; } static int string_to_number(const char *s, int min, int max) { long number; char *end; errno = 0; number = strtol(s, &end, 10); if (*end == '\0' && end != s) { /* We parsed a number, let's see if we want this. */ if (errno != ERANGE && min <= number && number <= max) return number; } return -1; } /* * Parse the timeout value. */ static int parse_timeout(char *buf, int min, int max) { int i; /* it is just for parsing timeout of persistent service */ if (buf == NULL) return IPVS_SVC_PERSISTENT_TIMEOUT; if ((i=string_to_number(buf, min, max)) == -1) fail(2, "invalid timeout value `%s' specified", buf); return i; } /* * Parse IP fwmark from the argument. */ static unsigned int parse_fwmark(char *buf) { unsigned long l; char *end; errno = 0; l = strtol(buf, &end, 10); if (*end != '\0' || end == buf || errno == ERANGE || l <= 0 || l > UINT_MAX) fail(2, "invalid fwmark value `%s' specified", buf); return l; } /* * Get netmask. * Return 0 if failed, * 1 if addr read */ static int parse_netmask(char *buf, u_int32_t *addr) { struct in_addr inaddr; if(buf == NULL) return 0; if (inet_aton(buf, &inaddr) != 0) *addr = inaddr.s_addr; else if (host_to_addr(buf, &inaddr) != -1) *addr = inaddr.s_addr; else return 0; return 1; } /* * Get IP address and port from the argument. * Result is a logical or of * SERVICE_NONE: no service elements set/error * SERVICE_ADDR: addr set * SERVICE_PORT: port set */ static int parse_service(char *buf, ipvs_service_t *svc) { char *portp = NULL; long portn; int result=SERVICE_NONE; struct in_addr inaddr; struct in6_addr inaddr6; if (buf == NULL || str_is_digit(buf)) return SERVICE_NONE; if (buf[0] == '[') { buf++; portp = strchr(buf, ']'); if (portp == NULL) return SERVICE_NONE; *portp = '\0'; portp++; if (*portp == ':') *portp = '\0'; else return SERVICE_NONE; } if (inet_pton(AF_INET6, buf, &inaddr6) > 0) { svc->addr.in6 = inaddr6; svc->af = AF_INET6; svc->netmask = 128; } else { portp = strrchr(buf, ':'); if (portp != NULL) *portp = '\0'; if (inet_aton(buf, &inaddr) != 0) { svc->addr.ip = inaddr.s_addr; svc->af = AF_INET; } else if (host_to_addr(buf, &inaddr) != -1) { svc->addr.ip = inaddr.s_addr; svc->af = AF_INET; } else return SERVICE_NONE; } result |= SERVICE_ADDR; if (portp != NULL) { result |= SERVICE_PORT; if ((portn = string_to_number(portp+1, 0, 65535)) != -1) svc->port = htons(portn); else if ((portn = service_to_port(portp+1, svc->protocol)) != -1) svc->port = htons(portn); else return SERVICE_NONE; } return result; } static void generic_opt_check(int command, int options) { int i, j; int last = 0, count = 0; /* Check that commands are valid with options. */ i = command - CMD_NONE -1; for (j = 0; j < NUMBER_OF_OPT; j++) { if (!(options & (1< 1; option >>= 1, ptr++); return *ptr; } static void set_command(int *cmd, const int newcmd) { if (*cmd != CMD_NONE) fail(2, "multiple commands specified"); *cmd = newcmd; } static void set_option(unsigned int *options, unsigned int option) { if (*options & option) fail(2, "multiple '%s' options specified", opt2name(option)); *options |= option; } static void tryhelp_exit(const char *program, const int exit_status) { fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", program, program); exit(exit_status); } static void usage_exit(const char *program, const int exit_status) { FILE *stream; if (exit_status != 0) stream = stderr; else stream = stdout; version(stream); fprintf(stream, "Usage:\n" " %s -A|E -t|u|f service-address [-s scheduler] [-p [timeout]] [-M netmask] [--pe persistence_engine]\n" " %s -D -t|u|f service-address\n" " %s -C\n" " %s -R\n" " %s -S [-n]\n" " %s -a|e -t|u|f service-address -r server-address [options]\n" " %s -d -t|u|f service-address -r server-address\n" " %s -L|l [options]\n" " %s -Z [-t|u|f service-address]\n" " %s --set tcp tcpfin udp\n" " %s --start-daemon state [--mcast-interface interface] [--syncid sid]\n" " %s --stop-daemon state\n" " %s -h\n\n", program, program, program, program, program, program, program, program, program, program, program, program, program); fprintf(stream, "Commands:\n" "Either long or short options are allowed.\n" " --add-service -A add virtual service with options\n" " --edit-service -E edit virtual service with options\n" " --delete-service -D delete virtual service\n" " --clear -C clear the whole table\n" " --restore -R restore rules from stdin\n" " --save -S save rules to stdout\n" " --add-server -a add real server with options\n" " --edit-server -e edit real server with options\n" " --delete-server -d delete real server\n" " --list -L|-l list the table\n" " --zero -Z zero counters in a service or all services\n" " --set tcp tcpfin udp set connection timeout values\n" " --start-daemon start connection sync daemon\n" " --stop-daemon stop connection sync daemon\n" " --help -h display this help message\n\n" ); fprintf(stream, "Options:\n" " --tcp-service -t service-address service-address is host[:port]\n" " --udp-service -u service-address service-address is host[:port]\n" " --fwmark-service -f fwmark fwmark is an integer greater than zero\n" " --ipv6 -6 fwmark entry uses IPv6\n" " --scheduler -s scheduler one of " SCHEDULERS ",\n" " the default scheduler is %s.\n" " --pe engine alternate persistence engine may be " PE_LIST ",\n" " not set by default.\n" " --persistent -p [timeout] persistent service\n" " --netmask -M netmask persistent granularity mask\n" " --real-server -r server-address server-address is host (and port)\n" " --gatewaying -g gatewaying (direct routing) (default)\n" " --ipip -i ipip encapsulation (tunneling)\n" " --masquerading -m masquerading (NAT)\n" " --weight -w weight capacity of real server\n" " --u-threshold -x uthreshold upper threshold of connections\n" " --l-threshold -y lthreshold lower threshold of connections\n" " --mcast-interface interface multicast interface for connection sync\n" " --syncid sid syncid for connection sync (default=255)\n" " --connection -c output of current IPVS connections\n" " --timeout output of timeout (tcp tcpfin udp)\n" " --daemon output of daemon information\n" " --stats output of statistics information\n" " --rate output of rate information\n" " --exact expand numbers (display exact values)\n" " --thresholds output of thresholds information\n" " --persistent-conn output of persistent connection info\n" " --nosort disable sorting output of service/server entries\n" " --sort does nothing, for backwards compatibility\n" " --ops -o one-packet scheduling\n" " --numeric -n numeric output of addresses and ports\n", DEF_SCHED); exit(exit_status); } static void version_exit(const int exit_status) { FILE *stream; if (exit_status != 0) stream = stderr; else stream = stdout; version(stream); exit(exit_status); } static void version(FILE *stream) { fprintf(stream, "ipvsadm " IPVSADM_VERSION " (compiled with " IPVS_OPTION_PROCESSING " and IPVS v%d.%d.%d)\n", NVERSION(IP_VS_VERSION_CODE)); } static void fail(int err, char *msg, ...) { va_list args; va_start(args, msg); vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, "\n"); exit(err); } static int modprobe_ipvs(void) { char *argv[] = { "/sbin/modprobe", "--", "ip_vs", NULL }; int child; int status; int rc; if (!(child = fork())) { execv(argv[0], argv); exit(1); } rc = waitpid(child, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status)) { return 1; } return 0; } static void check_ipvs_version(void) { /* verify the IPVS version */ if (ipvs_info.version < IPVS_VERSION(MINIMUM_IPVS_VERSION_MAJOR, MINIMUM_IPVS_VERSION_MINOR, MINIMUM_IPVS_VERSION_PATCH)) { fprintf(stderr, "Warning: IPVS version mismatch: \n" " Kernel compiled with IPVS version %d.%d.%d\n" " ipvsadm " IPVSADM_VERSION_NO " requires minimum IPVS version %d.%d.%d\n\n", NVERSION(ipvs_info.version), MINIMUM_IPVS_VERSION_MAJOR, MINIMUM_IPVS_VERSION_MINOR, MINIMUM_IPVS_VERSION_PATCH); } } static void print_conn(char *buf, unsigned int format) { char protocol[8]; unsigned short proto; union nf_inet_addr caddr; unsigned short cport; union nf_inet_addr vaddr; unsigned short vport; union nf_inet_addr daddr; unsigned short dport; char state[16]; unsigned int expires; unsigned short af = AF_INET; char pe_name[IP_VS_PENAME_MAXLEN]; char pe_data[IP_VS_PEDATA_MAXLEN]; int n; char temp1[INET6_ADDRSTRLEN], temp2[INET6_ADDRSTRLEN], temp3[INET6_ADDRSTRLEN]; char *cname, *vname, *dname; unsigned int minutes, seconds; char expire_str[12]; if ((n = sscanf(buf, "%s %s %hX %s %hX %s %hX %s %d %s %s", protocol, temp1, &cport, temp2, &vport, temp3, &dport, state, &expires, pe_name, pe_data)) == -1) exit(1); if (strcmp(protocol, "TCP") == 0) proto = IPPROTO_TCP; else if (strcmp(protocol, "UDP") == 0) proto = IPPROTO_UDP; else proto = 0; if (inet_pton(AF_INET6, temp1, &caddr.in6) > 0) { inet_pton(AF_INET6, temp2, &vaddr.in6); inet_pton(AF_INET6, temp3, &daddr.in6); af = AF_INET6; } else if (inet_pton(AF_INET, temp1, &caddr.ip) > 0) { inet_pton(AF_INET, temp2, &vaddr.ip); inet_pton(AF_INET, temp3, &daddr.ip); } else { caddr.ip = (__u32) htonl(strtoul(temp1, NULL, 16)); vaddr.ip = (__u32) htonl(strtoul(temp2, NULL, 16)); daddr.ip = (__u32) htonl(strtoul(temp3, NULL, 16)); } if (!(cname = addrport_to_anyname(af, &caddr, cport, proto, format))) exit(1); if (!(vname = addrport_to_anyname(af, &vaddr, vport, proto, format))) exit(1); if (!(dname = addrport_to_anyname(af, &daddr, dport, proto, format))) exit(1); seconds = expires % 60; minutes = expires / 60; sprintf(expire_str, "%02d:%02d", minutes, seconds); if (format & FMT_PERSISTENTCONN && n == 11) printf("%-3s %-6s %-11s %-18s %-18s %-16s %-18s %s\n", protocol, expire_str, state, cname, vname, dname, pe_name, pe_data); else printf("%-3s %-6s %-11s %-18s %-18s %s\n", protocol, expire_str, state, cname, vname, dname); free(cname); free(vname); free(dname); } void list_conn(unsigned int format) { static char buffer[256]; FILE *handle; handle = fopen(CONN_PROC_FILE, "r"); if (!handle) { fprintf(stderr, "cannot open file %s\n", CONN_PROC_FILE); exit(1); } /* read the first line */ if (fgets(buffer, sizeof(buffer), handle) == NULL) { fprintf(stderr, "unexpected input from %s\n", CONN_PROC_FILE); exit(1); } printf("IPVS connection entries\n"); if (format & FMT_PERSISTENTCONN) printf("pro expire %-11s %-18s %-18s %-18s %-16s %s\n", "state", "source", "virtual", "destination", "pe name", "pe_data"); else printf("pro expire %-11s %-18s %-18s %s\n", "state", "source", "virtual", "destination"); /* * Print the VS information according to the format */ while (!feof(handle)) { if (fgets(buffer, sizeof(buffer), handle)) print_conn(buffer, format); } fclose(handle); } static inline char *fwd_name(unsigned flags) { char *fwd = NULL; switch (flags & IP_VS_CONN_F_FWD_MASK) { case IP_VS_CONN_F_MASQ: fwd = "Masq"; break; case IP_VS_CONN_F_LOCALNODE: fwd = "Local"; break; case IP_VS_CONN_F_TUNNEL: fwd = "Tunnel"; break; case IP_VS_CONN_F_DROUTE: fwd = "Route"; break; } return fwd; } static inline char *fwd_switch(unsigned flags) { char *swt = NULL; switch (flags & IP_VS_CONN_F_FWD_MASK) { case IP_VS_CONN_F_MASQ: swt = "-m"; break; case IP_VS_CONN_F_TUNNEL: swt = "-i"; break; case IP_VS_CONN_F_LOCALNODE: case IP_VS_CONN_F_DROUTE: swt = "-g"; break; } return swt; } static void print_largenum(unsigned long long i, unsigned int format) { char mytmp[32]; size_t len; if (format & FMT_EXACT) { len = snprintf(mytmp, 32, "%llu", i); printf("%*llu", len <= 8 ? 9 : len + 1, i); return; } if (i < 100000000) /* less than 100 million */ printf("%9llu", i); else if (i < 1000000000) /* less than 1 billion */ printf("%8lluK", i / 1000); else if (i < 100000000000ULL) /* less than 100 billion */ printf("%8lluM", i / 1000000); else if (i < 100000000000000ULL) /* less than 100 trillion */ printf("%8lluG", i / 1000000000ULL); else printf("%8lluT", i / 1000000000000ULL); } static void print_title(unsigned int format) { if (format & FMT_STATS) printf("%-33s %8s %8s %8s %8s %8s\n" " -> RemoteAddress:Port\n", "Prot LocalAddress:Port", "Conns", "InPkts", "OutPkts", "InBytes", "OutBytes"); else if (format & FMT_RATE) printf("%-33s %8s %8s %8s %8s %8s\n" " -> RemoteAddress:Port\n", "Prot LocalAddress:Port", "CPS", "InPPS", "OutPPS", "InBPS", "OutBPS"); else if (format & FMT_THRESHOLDS) printf("%-33s %-10s %-10s %-10s %-10s\n" " -> RemoteAddress:Port\n", "Prot LocalAddress:Port", "Uthreshold", "Lthreshold", "ActiveConn", "InActConn"); else if (format & FMT_PERSISTENTCONN) printf("%-33s %-9s %-11s %-10s %-10s\n" " -> RemoteAddress:Port\n", "Prot LocalAddress:Port", "Weight", "PersistConn", "ActiveConn", "InActConn"); else if (!(format & FMT_RULE)) printf("Prot LocalAddress:Port Scheduler Flags\n" " -> RemoteAddress:Port Forward Weight ActiveConn InActConn\n"); } static void print_service_entry(ipvs_service_entry_t *se, unsigned int format) { struct ip_vs_get_dests *d; char svc_name[64]; int i; if (!(d = ipvs_get_dests(se))) { fprintf(stderr, "%s\n", ipvs_strerror(errno)); exit(1); } if (se->fwmark) { if (format & FMT_RULE) if (se->af == AF_INET6) sprintf(svc_name, "-f %d -6", se->fwmark); else sprintf(svc_name, "-f %d", se->fwmark); else if (se->af == AF_INET6) sprintf(svc_name, "FWM %d IPv6", se->fwmark); else sprintf(svc_name, "FWM %d", se->fwmark); } else { char *vname; if (!(vname = addrport_to_anyname(se->af, &se->addr, ntohs(se->port), se->protocol, format))) fail(2, "addrport_to_anyname: %s", strerror(errno)); if (format & FMT_RULE) sprintf(svc_name, "%s %s", se->protocol==IPPROTO_TCP?"-t":"-u", vname); else { sprintf(svc_name, "%s %s", se->protocol==IPPROTO_TCP?"TCP":"UDP", vname); if (se->af != AF_INET6) svc_name[33] = '\0'; } free(vname); } /* print virtual service info */ if (format & FMT_RULE) { printf("-A %s -s %s", svc_name, se->sched_name); if (se->flags & IP_VS_SVC_F_PERSISTENT) { printf(" -p %u", se->timeout); if (se->af == AF_INET) if (se->netmask != (unsigned long int) 0xffffffff) { struct in_addr mask; mask.s_addr = se->netmask; printf(" -M %s", inet_ntoa(mask)); } if (se->af == AF_INET6) if (se->netmask != 128) { printf(" -M %i", se->netmask); } } if (se->pe_name[0]) printf(" pe %s", se->pe_name); if (se->flags & IP_VS_SVC_F_ONEPACKET) printf(" ops"); } else if (format & FMT_STATS) { printf("%-33s", svc_name); print_largenum(se->stats.conns, format); print_largenum(se->stats.inpkts, format); print_largenum(se->stats.outpkts, format); print_largenum(se->stats.inbytes, format); print_largenum(se->stats.outbytes, format); } else if (format & FMT_RATE) { printf("%-33s", svc_name); print_largenum(se->stats.cps, format); print_largenum(se->stats.inpps, format); print_largenum(se->stats.outpps, format); print_largenum(se->stats.inbps, format); print_largenum(se->stats.outbps, format); } else { printf("%s %s", svc_name, se->sched_name); if (se->flags & IP_VS_SVC_F_PERSISTENT) { printf(" persistent %u", se->timeout); if (se->af == AF_INET) if (se->netmask != (unsigned long int) 0xffffffff) { struct in_addr mask; mask.s_addr = se->netmask; printf(" mask %s", inet_ntoa(mask)); } if (se->af == AF_INET6) if (se->netmask != 128) printf(" mask %i", se->netmask); if (se->pe_name[0]) printf(" pe %s", se->pe_name); if (se->flags & IP_VS_SVC_F_ONEPACKET) printf(" ops"); } } printf("\n"); /* print all the destination entries */ if (!(format & FMT_NOSORT)) ipvs_sort_dests(d, ipvs_cmp_dests); for (i = 0; i < d->num_dests; i++) { char *dname; ipvs_dest_entry_t *e = &d->entrytable[i]; if (!(dname = addrport_to_anyname(se->af, &(e->addr), ntohs(e->port), se->protocol, format))) { fprintf(stderr, "addrport_to_anyname fails\n"); exit(1); } if (!(format & FMT_RULE) && (se->af != AF_INET6)) dname[28] = '\0'; if (format & FMT_RULE) { printf("-a %s -r %s %s -w %d\n", svc_name, dname, fwd_switch(e->conn_flags), e->weight); } else if (format & FMT_STATS) { printf(" -> %-28s", dname); print_largenum(e->stats.conns, format); print_largenum(e->stats.inpkts, format); print_largenum(e->stats.outpkts, format); print_largenum(e->stats.inbytes, format); print_largenum(e->stats.outbytes, format); printf("\n"); } else if (format & FMT_RATE) { printf(" -> %-28s %8u %8u %8u", dname, e->stats.cps, e->stats.inpps, e->stats.outpps); print_largenum(e->stats.inbps, format); print_largenum(e->stats.outbps, format); printf("\n"); } else if (format & FMT_THRESHOLDS) { printf(" -> %-28s %-10u %-10u %-10u %-10u\n", dname, e->u_threshold, e->l_threshold, e->activeconns, e->inactconns); } else if (format & FMT_PERSISTENTCONN) { printf(" -> %-28s %-9u %-11u %-10u %-10u\n", dname, e->weight, e->persistconns, e->activeconns, e->inactconns); } else printf(" -> %-28s %-7s %-6d %-10u %-10u\n", dname, fwd_name(e->conn_flags), e->weight, e->activeconns, e->inactconns); free(dname); } free(d); } static void list_service(ipvs_service_t *svc, unsigned int format) { ipvs_service_entry_t *entry; if (!(entry = ipvs_get_service(svc->fwmark, svc->af, svc->protocol, svc->addr, svc->port))) { fprintf(stderr, "%s\n", ipvs_strerror(errno)); exit(1); } print_title(format); print_service_entry(entry, format); free(entry); } static void list_all(unsigned int format) { struct ip_vs_get_services *get; int i; if (!(format & FMT_RULE)) printf("IP Virtual Server version %d.%d.%d (size=%d)\n", NVERSION(ipvs_info.version), ipvs_info.size); if (!(get = ipvs_get_services())) { fprintf(stderr, "%s\n", ipvs_strerror(errno)); exit(1); } if (!(format & FMT_NOSORT)) ipvs_sort_services(get, ipvs_cmp_services); print_title(format); for (i = 0; i < get->num_services; i++) print_service_entry(&get->entrytable[i], format); free(get); } void list_timeout(void) { ipvs_timeout_t *u; if (!(u = ipvs_get_timeout())) exit(1); printf("Timeout (tcp tcpfin udp): %d %d %d\n", u->tcp_timeout, u->tcp_fin_timeout, u->udp_timeout); free(u); } static void list_daemon(void) { ipvs_daemon_t *u; if (!(u = ipvs_get_daemon())) exit(1); if (u[0].state & IP_VS_STATE_MASTER) printf("master sync daemon (mcast=%s, syncid=%d)\n", u[0].mcast_ifn, u[0].syncid); if (u[1].state & IP_VS_STATE_BACKUP) printf("backup sync daemon (mcast=%s, syncid=%d)\n", u[1].mcast_ifn, u[1].syncid); free(u); } int host_to_addr(const char *name, struct in_addr *addr) { struct hostent *host; if ((host = gethostbyname(name)) != NULL) { if (host->h_addrtype != AF_INET || host->h_length != sizeof(struct in_addr)) return -1; /* warning: we just handle h_addr_list[0] here */ memcpy(addr, host->h_addr_list[0], sizeof(struct in_addr)); return 0; } return -1; } static char * addr_to_host(int af, const void *addr) { struct hostent *host; if ((host = gethostbyaddr((char *) addr, sizeof(struct in_addr), af)) != NULL) return (char *) host->h_name; else return (char *) NULL; } static char * addr_to_anyname(int af, const void *addr) { char *name; static char buf[INET6_ADDRSTRLEN]; if ((name = addr_to_host(af, addr)) != NULL) return name; inet_ntop(af, addr, buf, sizeof(buf)); return buf; } int service_to_port(const char *name, unsigned short proto) { struct servent *service; if (proto == IPPROTO_TCP && (service = getservbyname(name, "tcp")) != NULL) return ntohs((unsigned short) service->s_port); else if (proto == IPPROTO_UDP && (service = getservbyname(name, "udp")) != NULL) return ntohs((unsigned short) service->s_port); else return -1; } static char * port_to_service(unsigned short port, unsigned short proto) { struct servent *service; if (proto == IPPROTO_TCP && (service = getservbyport(htons(port), "tcp")) != NULL) return service->s_name; else if (proto == IPPROTO_UDP && (service = getservbyport(htons(port), "udp")) != NULL) return service->s_name; else return (char *) NULL; } static char * port_to_anyname(unsigned short port, unsigned short proto) { char *name; static char buf[10]; if ((name = port_to_service(port, proto)) != NULL) return name; else { sprintf(buf, "%u", port); return buf; } } static char * addrport_to_anyname(int af, const void *addr, unsigned short port, unsigned short proto, unsigned int format) { char *buf, pbuf[INET6_ADDRSTRLEN]; if (!(buf=malloc(60))) return NULL; if (format & FMT_NUMERIC) { snprintf(buf, 60, "%s%s%s:%u", af == AF_INET ? "" : "[", inet_ntop(af, addr, pbuf, sizeof(pbuf)), af == AF_INET ? "" : "]", port); } else { snprintf(buf, 60, "%s%s%s:%s", af == AF_INET ? "" : "[", addr_to_anyname(af, addr), af == AF_INET ? "" : "]", port_to_anyname(port, proto)); } return buf; } static int str_is_digit(const char *str) { size_t offset; size_t top; top = strlen(str); for (offset=0; offset # # This file: # # ChangeLog # Horms : Clear IPVS rules before adding from STDIN # Horms : Filter out "^#" # # PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin # All the work is actually done in ipvsadm, hooray INPUT="$(grep -v '^#')" ipvsadm -C echo "$INPUT" | ipvsadm -R ipvsadm-1.26/ipvsadm-restore.80000664000076400007640000000107211064475161016263 0ustar wensongwensong.\" .\" ipvsadm-restore(8) manual page .\" Inspired by ipchains-restore .\" .\" $Id: ipvsadm-restore.8 49 2001-03-27 09:27:54Z wensong $ .\" .\" Authors: Wensong Zhang .\" .\" Changes: .\" .\" .TH IPVSADM-RESTORE 8 "22nd March 2001" "LVS Administration" "Linux Administrator's Guide" .SH NAME ipvsadm\-restore \- restore the IPVS table from stdin .SH SYNOPSIS .BR "ipvsadm\-restore " .SH DESCRIPTION ipvsadm\-restore prints the IPVS table from stdin. .SH OPTIONS No options now. .SH SEE ALSO ipvsadm(8), the LVS\-HOWTO. ipvsadm-1.26/ipvsadm-save0000664000076400007640000000142711064475161015374 0ustar wensongwensong#!/bin/bash # ipvsadm-save - Save IPVS rules # # A very simple wrapper to save IPVS rules # Inspired by ipchains-save. # # Version: $Id: ipvsadm-save 49 2001-03-27 09:27:54Z wensong $ # # Script Author: Horms # # This file: # # ChangeLog # # Wensong Zhang : Added the "-n" option and the help() # PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin NUMERIC="" help() { exec 1>&2 echo `basename $0`: Script to save the IPVS table to stdout. echo " With the -n option, prints out the table in numeric format." exit 1 } for arg do case "$arg" in -n) NUMERIC="-n" ;; -*) help ;; esac done # All the work is actually done in ipvsadm, horay ipvsadm -S $NUMERIC ipvsadm-1.26/ipvsadm-save.80000664000076400007640000000117611064475161015543 0ustar wensongwensong.\" .\" ipvsadm-save(8) manual page .\" Inspired by ipchains-save .\" .\" $Id: ipvsadm-save.8 49 2001-03-27 09:27:54Z wensong $ .\" .\" Authors: Wensong Zhang .\" .\" Changes: .\" .\" .TH IPVSADM-SAVE 8 "22nd March 2001" "LVS Administration" "Linux Administrator's Guide" .SH NAME ipvsadm\-save \- save the IPVS table to stdout .SH SYNOPSIS .BR "ipvsadm\-save " [ -n ] .SH DESCRIPTION ipvsadm\-save prints the IPVS table to stdout. .SH OPTIONS The option that is recognized by .B ipvsadm-save is: .TP .BR -n print out the table in numeric format. .SH SEE ALSO ipvsadm(8), the LVS\-HOWTO. ipvsadm-1.26/ipvsadm.sh0000664000076400007640000000456711064475161015061 0ustar wensongwensong#!/bin/sh # # Startup script handle the initialisation of LVS # # chkconfig: - 08 92 # # description: Initialise the Linux Virtual Server # http://www.linuxvirtualserver.org/ # # Script Author: Horms # # Based on init script for ipchains by Joshua Jensen # # Changes: # Wenzhuo Zhang : fixed the typo of failure function # # config: /etc/sysconfig/ipvsadm # config: /etc/ipvsadm.rules # set the configuration file if [ -f "/etc/sysconfig/ipvsadm" ]; then IPVSADM_CONFIG="/etc/sysconfig/ipvsadm" elif [ -f "/etc/ipvsadm.rules" ]; then IPVSADM_CONFIG="/etc/ipvsadm.rules" else IPVSADM_CONFIG="/etc/sysconfig/ipvsadm" fi # Use the funtions provided by Red Hat or use our own if [ -f /etc/rc.d/init.d/functions ] then . /etc/rc.d/init.d/functions else function action { echo "$1" shift $@ } function success { echo -n "Success" } function failure { echo -n "Failed" } fi # Check for ipvsadm in both /sbin and /usr/sbin # The default install puts it in /sbin, as it is analogos to commands such # as route and ipchains that live in /sbin. Some vendors, most notibly # Red Hat insist on moving it to /usr/sbin if [ ! -x /sbin/ipvsadm -a ! -x /usr/sbin/ipvsadm ]; then exit 0 fi case "$1" in start) # If we don't clear these first, we might be adding to # pre-existing rules. action "Clearing the current IPVS table:" ipvsadm -C echo -n "Applying IPVS configuration: " ipvsadm-restore < "$IPVSADM_CONFIG" && \ success "Applying IPVS configuration" || \ failure "Applying IPVS configuration" echo touch /var/lock/subsys/ipvsadm ;; stop) action "Clearing the current IPVS table:" ipvsadm -C rm -f /var/lock/subsys/ipvsadm ;; reload|reload-force|restart) #Start should flush everything $0 start ;; panic) # I'm not sure what panic does but in the case of IPVS # it makes sense just to clear everything action "Clearing the current IPVS table:" ipvsadm -C ;; status) ipvsadm -L -n ;; save) echo -n "Saving IPVS table to $IPVSADM_CONFIG: " ipvsadm-save -n > $IPVSADM_CONFIG 2>/dev/null && \ success "Saving IPVS table to $IPVSADM_CONFIG" || \ failure "Saving IPVS table to $IPVSADM_CONFIG" echo ;; *) echo "Usage: ipvsadm {start|stop|restart|status|panic|save|reload|reload-force}" exit 1 esac exit 0 ipvsadm-1.26/ipvsadm.spec0000664000076400007640000000537411524106600015364 0ustar wensongwensong%define prefix /usr Summary: Utility to administer the Linux Virtual Server Name: ipvsadm Version: 1.26 Release: 1 License: GPL URL: http://www.LinuxVirtualServer.org/ Group: Applications/System Source0: http://www.LinuxVirtualServer.org/software/ipvsadm-%{version}.tar.gz BuildRoot: /var/tmp/%name-%{PACKAGE_VERSION}-root Provides: %{name}-%{version} Conflicts: piranha <= 0.4.14 %description ipvsadm is a utility to administer the IP Virtual Server services offered by the latest Linux kernel 2.6.x. %prep %setup -n %{name}-%{version} %build CFLAGS="${RPM_OPT_FLAGS}" make %install rm -rf $RPM_BUILD_ROOT mkdir -p ${RPM_BUILD_ROOT}/{sbin,%{_mandir}/man8,etc/rc.d/init.d} make install BUILD_ROOT=${RPM_BUILD_ROOT} MANDIR=%{_mandir} %files %defattr(-,root,root) %doc README %config /etc/rc.d/init.d/ipvsadm /sbin/ipvsadm* %{_mandir}/man8/ipvsadm* %post /sbin/chkconfig --add ipvsadm %preun /sbin/chkconfig --del ipvsadm %clean rm -rf $RPM_BUILD_DIR/%{name} rm -rf $RPM_BUILD_ROOT %changelog * Thu Jun 23 2005 Steve Nielsen - Respect rpmmacros that might be set (by using rpm --eval) * Sat Dec 20 2003 Wensong Zhang - tidy up the description * Sat Apr 5 2003 Wensong Zhang - Removed the unnecessary Docdir setting. * Thu Dec 16 2001 Wensong Zhang - Changed to install ipvsadm man pages according to the %{_mandir} * Thu Dec 30 2000 Wensong Zhang - update the %file section * Thu Dec 17 2000 Wensong Zhang - Added a if-condition to keep both new or old rpm utility building the package happily. * Tue Dec 12 2000 P.Copeland - Small modifications to make the compiler happy in RH7 and the Alpha - Fixed the documentation file that got missed off in building the rpm - Made a number of -pedantic mods though popt will not compile with -pedantic * Wed Aug 9 2000 Horms - Removed Obseletes tag as ipvsadm is back in /sbin where it belongs as it is more or less analogous to both route and ipchains both of which reside in /sbin. - Create directory to install init script into. Init scripts won't install into build directory unless this is done * Thu Jul 6 2000 Wensong Zhang - Changed to build rpms on the ipvsadm tar ball directly * Wed Jun 21 2000 P.Copeland - fixed silly install permission settings * Mon Jun 19 2000 P.Copeland - Added 'dist' and 'rpms' to the Makefile - Added Obsoletes tag since there were early versions of ipvsadm-*.rpm that installed in /sbin - Obsolete tag was a bit vicious re: piranha * Mon Apr 10 2000 Horms - created for version 1.9 ipvsadm-1.26/ipvsadm.spec.in0000664000076400007640000000541511064475161015777 0ustar wensongwensong%define prefix /usr Summary: Utility to administer the Linux Virtual Server Name: ipvsadm Version: @@VERSION@@ Release: @@RELEASE@@ License: GPL URL: http://www.LinuxVirtualServer.org/ Group: Applications/System Source0: http://www.LinuxVirtualServer.org/software/ipvsadm-%{version}.tar.gz BuildRoot: /var/tmp/%name-%{PACKAGE_VERSION}-root Provides: %{name}-%{version} Conflicts: piranha <= 0.4.14 %description ipvsadm is a utility to administer the IP Virtual Server services offered by the latest Linux kernel 2.6.x. %prep %setup -n %{name}-%{version} %build CFLAGS="${RPM_OPT_FLAGS}" make %install rm -rf $RPM_BUILD_ROOT mkdir -p ${RPM_BUILD_ROOT}/{sbin,%{_mandir}/man8,etc/rc.d/init.d} make install BUILD_ROOT=${RPM_BUILD_ROOT} MANDIR=%{_mandir} %files %defattr(-,root,root) %doc README %config /etc/rc.d/init.d/ipvsadm /sbin/ipvsadm* %{_mandir}/man8/ipvsadm* %post /sbin/chkconfig --add ipvsadm %preun /sbin/chkconfig --del ipvsadm %clean rm -rf $RPM_BUILD_DIR/%{name} rm -rf $RPM_BUILD_ROOT %changelog * Thu Jun 23 2005 Steve Nielsen - Respect rpmmacros that might be set (by using rpm --eval) * Sat Dec 20 2003 Wensong Zhang - tidy up the description * Sat Apr 5 2003 Wensong Zhang - Removed the unnecessary Docdir setting. * Thu Dec 16 2001 Wensong Zhang - Changed to install ipvsadm man pages according to the %{_mandir} * Thu Dec 30 2000 Wensong Zhang - update the %file section * Thu Dec 17 2000 Wensong Zhang - Added a if-condition to keep both new or old rpm utility building the package happily. * Tue Dec 12 2000 P.Copeland - Small modifications to make the compiler happy in RH7 and the Alpha - Fixed the documentation file that got missed off in building the rpm - Made a number of -pedantic mods though popt will not compile with -pedantic * Wed Aug 9 2000 Horms - Removed Obseletes tag as ipvsadm is back in /sbin where it belongs as it is more or less analogous to both route and ipchains both of which reside in /sbin. - Create directory to install init script into. Init scripts won't install into build directory unless this is done * Thu Jul 6 2000 Wensong Zhang - Changed to build rpms on the ipvsadm tar ball directly * Wed Jun 21 2000 P.Copeland - fixed silly install permission settings * Mon Jun 19 2000 P.Copeland - Added 'dist' and 'rpms' to the Makefile - Added Obsoletes tag since there were early versions of ipvsadm-*.rpm that installed in /sbin - Obsolete tag was a bit vicious re: piranha * Mon Apr 10 2000 Horms - created for version 1.9 ipvsadm-1.26/libipvs/0000775000076400007640000000000011524106513014507 5ustar wensongwensongipvsadm-1.26/libipvs/ip_vs.h0000664000076400007640000003575711523655501016026 0ustar wensongwensong/* * IP Virtual Server * data structure and functionality definitions */ #ifndef _IP_VS_H #define _IP_VS_H #include #include #include #include /* For __beXX types in userland */ #ifdef LIBIPVS_USE_NL #include #include #include #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 */ #define IP_VS_SVC_F_ONEPACKET 0x0004 /* one-packet scheduling */ /* * 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 */ #define IP_VS_CONN_F_ONE_PACKET 0x2000 /* forward only one packet */ #define IP_VS_SCHEDNAME_MAXLEN 16 #define IP_VS_PENAME_MAXLEN 16 #define IP_VS_IFNAME_MAXLEN 16 #define IP_VS_PEDATA_MAXLEN 255 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; char pe_name[IP_VS_PENAME_MAXLEN]; }; 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; char pe_name[IP_VS_PENAME_MAXLEN]; }; 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_PE_NAME, /* name of scheduler */ __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 */ ipvsadm-1.26/libipvs/ip_vs_nl_policy.c0000664000076400007640000000542111064475161020054 0ustar wensongwensong#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 */ ipvsadm-1.26/libipvs/libipvs.c0000664000076400007640000007115411523655501016340 0ustar wensongwensong/* * 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 * * 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 #include #include #include #include #include #include #include #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 static struct nl_handle *sock = NULL; static 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; \ #define CHECK_PE(s, ret) if (s->pe_name) \ { errno = EAFNOSUPPORT; return ret; } #define CHECK_COMPAT_DEST(s, ret) CHECK_IPV4(s, ret) #define CHECK_COMPAT_SVC(s, ret) \ CHECK_IPV4(s, ret); \ CHECK_PE(s, ret); #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) { try_nl = 1; 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); if (svc->pe_name) NLA_PUT_STRING(msg, IPVS_SVC_ATTR_PE_NAME, svc->pe_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_COMPAT_SVC(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_COMPAT_SVC(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_COMPAT_SVC(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_COMPAT_SVC(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_COMPAT_SVC(svc, -1); CHECK_COMPAT_DEST(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_COMPAT_SVC(svc, -1); CHECK_COMPAT_DEST(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_COMPAT_SVC(svc, -1); CHECK_COMPAT_DEST(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); if (svc_attrs[IPVS_SVC_ATTR_PE_NAME]) strncpy(get->entrytable[i].pe_name, nla_get_string(svc_attrs[IPVS_SVC_ATTR_PE_NAME]), IP_VS_PENAME_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].persistconns = 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_COMPAT_SVC(svc, NULL); CHECK_PE(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; svc->pe_name[0] = '\0'; 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 or persistence engine not found" }, { ipvs_update_service, ESRCH, "No such service" }, { ipvs_update_service, ENOENT, "Scheduler or persistence engine 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); } ipvsadm-1.26/libipvs/Makefile0000664000076400007640000000132411065415633016155 0ustar wensongwensong# 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 ipvsadm-1.26/libipvs/libipvs.h0000664000076400007640000000747011064475161016347 0ustar wensongwensong/* * 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 * */ #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 */ ipvsadm-1.26/Makefile0000664000076400007640000001035511524106467014513 0ustar wensongwensong# # ipvsadm - IP Virtual Server ADMinistration program # for IPVS NetFilter Module in kernel 2.4 # # Version: $Id: Makefile 77 2011-02-08 00:23:51Z wensong $ # # Authors: Wensong Zhang # Peter Kese # # This file: # # ChangeLog # # Wensong : Modified the Makefile and the spec files so # : that rpms can be created with ipvsadm alone # P.Copeland : Modified the Makefile and the spec files so # : that it is possible to create rpms on the fly # : using 'make rpms' # : Also added NAME, VERSION and RELEASE numbers to # : the Makefile # Horms : Updated to add config_stream.c dynamic_array.c # : Added autodetection of libpot # : Added BUILD_ROOT support # Wensong : Changed the OBJS according to detection # Ratz : Fixed to use the correct CFLAGS on sparc64 # NAME = ipvsadm VERSION = $(shell cat VERSION) RELEASE = 1 SCHEDULERS = "$(shell cat SCHEDULERS)" PE_LIST = "$(shell cat PERSISTENCE_ENGINES)" PROGROOT = $(shell basename `pwd`) ARCH = $(shell uname -m) RPMSOURCEDIR = $(shell rpm --eval '%_sourcedir') RPMSPECDIR = $(shell rpm --eval '%_specdir') CC = gcc INCLUDE = SBIN = $(BUILD_ROOT)/sbin MANDIR = usr/man MAN = $(BUILD_ROOT)/$(MANDIR)/man8 INIT = $(BUILD_ROOT)/etc/rc.d/init.d MKDIR = mkdir INSTALL = install STATIC_LIBS = libipvs/libipvs.a ifeq "${ARCH}" "sparc64" CFLAGS = -Wall -Wunused -Wstrict-prototypes -g -m64 -pipe -mcpu=ultrasparc -mcmodel=medlow else CFLAGS = -Wall -Wunused -Wstrict-prototypes -g endif ##################################### # No servicable parts below this line RPMBUILD = $(shell \ if [ -x /usr/bin/rpmbuild ]; then \ echo "/usr/bin/rpmbuild"; \ else \ echo "/bin/rpm"; \ fi ) ifeq (,$(FORCE_GETOPT)) LIB_SEARCH = /lib64 /usr/lib64 /usr/local/lib64 /lib /usr/lib /usr/local/lib POPT_LIB = $(shell for i in $(LIB_SEARCH); do \ if [ -f $$i/libpopt.a ]; then \ if nm $$i/libpopt.a | fgrep -q poptGetContext; then \ echo "-lpopt"; \ break; \ fi; \ fi; \ done) endif ifneq (,$(POPT_LIB)) POPT_DEFINE = -DHAVE_POPT endif OBJS = ipvsadm.o config_stream.o dynamic_array.o LIBS = $(POPT_LIB) ifneq (0,$(HAVE_NL)) LIBS += -lnl endif DEFINES = -DVERSION=\"$(VERSION)\" -DSCHEDULERS=\"$(SCHEDULERS)\" \ -DPE_LIST=\"$(PE_LIST)\" $(POPT_DEFINE) DEFINES += $(shell if [ ! -f ../ip_vs.h ]; then \ echo "-DHAVE_NET_IP_VS_H"; fi;) .PHONY = all clean install dist distclean rpm rpms all: libs ipvsadm libs: make -C libipvs ipvsadm: $(OBJS) $(STATIC_LIBS) $(CC) $(CFLAGS) -o $@ $^ $(LIBS) install: all if [ ! -d $(SBIN) ]; then $(MKDIR) -p $(SBIN); fi $(INSTALL) -m 0755 ipvsadm $(SBIN) $(INSTALL) -m 0755 ipvsadm-save $(SBIN) $(INSTALL) -m 0755 ipvsadm-restore $(SBIN) [ -d $(MAN) ] || $(MKDIR) -p $(MAN) $(INSTALL) -m 0644 ipvsadm.8 $(MAN) $(INSTALL) -m 0644 ipvsadm-save.8 $(MAN) $(INSTALL) -m 0644 ipvsadm-restore.8 $(MAN) [ -d $(INIT) ] || $(MKDIR) -p $(INIT) $(INSTALL) -m 0755 ipvsadm.sh $(INIT)/ipvsadm clean: rm -f ipvsadm $(NAME).spec $(NAME)-$(VERSION).tar.gz rm -rf debian/tmp find . -name '*.[ao]' -o -name "*~" -o -name "*.orig" \ -o -name "*.rej" -o -name core | xargs rm -f make -C libipvs clean distclean: clean dist: distclean sed -e "s/@@VERSION@@/$(VERSION)/g" \ -e "s/@@RELEASE@@/$(RELEASE)/g" \ < ipvsadm.spec.in > ipvsadm.spec rm -f $(NAME)-$(VERSION) ln -s . $(NAME)-$(VERSION) tar czvf $(NAME)-$(VERSION).tar.gz \ --exclude CVS --exclude .svn --exclude TAGS \ --exclude $(NAME)-$(VERSION)/$(NAME)-$(VERSION) \ --exclude $(NAME)-$(VERSION).tar.gz \ $(NAME)-$(VERSION)/* rm -f $(NAME)-$(VERSION) rpms: dist cp $(NAME)-$(VERSION).tar.gz $(RPMSOURCEDIR)/ cp $(NAME).spec $(RPMSPECDIR)/ $(RPMBUILD) -ba $(RPMSPECDIR)/$(NAME).spec srpm: dist cp $(NAME)-$(VERSION).tar.gz $(RPMSOURCEDIR)/ cp $(NAME).spec $(RPMSPECDIR)/ $(RPMBUILD) -bs $(RPMSPECDIR)/$(NAME).spec deb: debs debs: dpkg-buildpackage %.o: %.c $(CC) $(CFLAGS) $(INCLUDE) $(DEFINES) -c -o $@ $< ipvsadm-1.26/PERSISTENCE_ENGINES0000664000076400007640000000000411524104652015712 0ustar wensongwensongsip ipvsadm-1.26/README0000664000076400007640000000373211064475161013733 0ustar wensongwensong-------------------------------------------------------------------------- ipvsadm - Version 1.20 - 18th September 2001 This is free software. See below for details. ipvsadm is a utility to administer the IP virtual server services offered by the Linux kernel with IP virtual server support. This version of ipvsadm requires IPVS module v0.9.7 for kernel 2.4 or later. Check out the Linux Virtual Server Project home page on the World Wide Web: http://www.LinuxVirtualServer.org/ or http://www.Linux-VS.org/ for the most recent information and original sources about ipvsadm. To make, make sure your Linux kernel is already patched with IPVS and "make menuconfig" or "make xconfig" to setup the right compiling options, see the README of the virtual server patch for detail, then simply type make in the source directory. Install to your liking. We suggest the following pathnames: /sbin/ipvsadm /sbin/ipvsadm-save /sbin/ipvsadm-restore /usr/man/man8/ipvsadm.8 /usr/man/man8/ipvsadm-save.8 /usr/man/man8/ipvsadm-restore.8 /etc/rc.d/init.d/ipvsadm This will be done automatically when calling make install in the source directory. Wensong Zhang -------------------------------------------------------------------------- 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -------------------------------------------------------------------- ipvsadm-1.26/SCHEDULERS0000664000076400007640000000004611064475161014432 0ustar wensongwensongrr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq ipvsadm-1.26/VERSION0000664000076400007640000000000511524105430014077 0ustar wensongwensong1.26