keepalived-1.2.13/0000755000175000017500000000000012334417517013532 5ustar acassenacassenkeepalived-1.2.13/keepalived.spec.in0000664000175000017500000001215612334413574017132 0ustar acassenacassen# $Id$ # Authority: dag # Ugly, but we need headers from a kernel to rebuild against %define kernel %(rpm -q kernel-devel --qf '%{RPMTAG_VERSION}-%{RPMTAG_RELEASE}\\n' 2>/dev/null | head -1) Summary: HA monitor built upon LVS, VRRP and services poller Name: keepalived Version: 1.2.13 Release: 5 License: GPL Group: Applications/System URL: http://www.keepalived.org/ Source0: http://www.keepalived.org/software/keepalived-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root BuildRequires: openssl-devel # We need both of these for proper LVS support BuildRequires: kernel, kernel-devel Requires(post): /sbin/chkconfig Requires(preun): /sbin/service, /sbin/chkconfig Requires(postun): /sbin/service %description The main goal of the keepalived project is to add a strong & robust keepalive facility to the Linux Virtual Server project. This project is written in C with multilayer TCP/IP stack checks. Keepalived implements a framework based on three family checks : Layer3, Layer4 & Layer5/7. This framework gives the daemon the ability to check the state of an LVS server pool. When one of the servers of the LVS server pool is down, keepalived informs the linux kernel via a setsockopt call to remove this server entry from the LVS topology. In addition keepalived implements an independent VRRPv2 stack to handle director failover. So in short keepalived is a userspace daemon for LVS cluster nodes healthchecks and LVS directors failover. %prep %setup %build %{?el3:export CPPFLAGS="-I/usr/kerberos/include"} %{?rh9:export CPPFLAGS="-I/usr/kerberos/include"} %configure \ %{?el3:--includedir="/usr/kerberos/include"} \ %{?rh9:--includedir="/usr/kerberos/include"} \ --with-kernel-dir="/lib/modules/%{kernel}/build" %{__make} %{?_smp_mflags} STRIP=/bin/true %install %{__rm} -rf %{buildroot} %{__make} install DESTDIR=%{buildroot} # Remove "samples", as we include them in %%doc %{__rm} -rf %{buildroot}%{_sysconfdir}/keepalived/samples/ %check # A build could silently have LVS support disabled if the kernel includes can't # be properly found, we need to avoid that. if ! grep -q "IPVS_SUPPORT='_WITH_LVS_'" config.log; then echo "ERROR: We do not want keeepalived lacking LVS support." exit 1 fi %clean %{__rm} -rf %{buildroot} %post /sbin/chkconfig --add keepalived %preun if [ $1 -eq 0 ]; then /sbin/service keepalived stop &>/dev/null || : /sbin/chkconfig --del keepalived fi %postun if [ $1 -ge 1 ]; then /sbin/service keepalived condrestart &>/dev/null || : fi %files %defattr(-, root, root, 0755) %doc AUTHOR ChangeLog CONTRIBUTORS COPYING README TODO %doc doc/keepalived.conf.SYNOPSIS doc/samples/ %dir %{_sysconfdir}/keepalived/ %attr(0600, root, root) %config(noreplace) %{_sysconfdir}/keepalived/keepalived.conf %attr(0600, root, root) %config(noreplace) %{_sysconfdir}/sysconfig/keepalived %{_sysconfdir}/rc.d/init.d/keepalived %{_bindir}/genhash %{_sbindir}/keepalived %{_mandir}/man1/genhash.1* %{_mandir}/man5/keepalived.conf.5* %{_mandir}/man8/keepalived.8* %changelog * Thu Sep 13 2007 Alexandre Cassen 1.1.14 - Merge work done by freshrpms.net... Thanks guys !!! ;) * Wed Feb 14 2007 Matthias Saou 1.1.13-5 - Add missing scriplet requirements. * Tue Feb 13 2007 Matthias Saou 1.1.13-4 - Add missing \n to the kernel define, for when multiple kernels are installed. - Pass STRIP=/bin/true to "make" in order to get a useful debuginfo package. * Tue Feb 13 2007 Matthias Saou 1.1.13-3 - Add %%check section to make sure any build without LVS support will fail. * Mon Feb 5 2007 Matthias Saou 1.1.13-2 - Use our own init script, include a sysconfig entry used by it for options. * Thu Jan 25 2007 Matthias Saou 1.1.13-1 - Update to 1.1.13. - Change mode of configuration file to 0600. - Don't include all of "doc" since it meant re-including all man pages. - Don't include samples in the main configuration path, they're in %%doc. - Include patch to add an optional label to interfaces. * Sat Apr 08 2006 Dries Verachtert - 1.1.12-1.2 - Rebuild for Fedora Core 5. * Sun Mar 12 2006 Dag Wieers - 1.1.12-1 - Updated to release 1.1.12. * Fri Mar 04 2005 Dag Wieers - 1.1.11-1 - Updated to release 1.1.11. * Wed Feb 23 2005 Dag Wieers - 1.1.10-2 - Fixed IPVS/LVS support. (Joe Sauer) * Tue Feb 15 2005 Dag Wieers - 1.1.10-1 - Updated to release 1.1.10. * Mon Feb 07 2005 Dag Wieers - 1.1.9-1 - Updated to release 1.1.9. * Sun Oct 17 2004 Dag Wieers - 1.1.7-2 - Fixes to build with kernel IPVS support. (Tim Verhoeven) * Fri Sep 24 2004 Dag Wieers - 1.1.7-1 - Updated to release 1.1.7. (Mathieu Lubrano) * Mon Feb 23 2004 Dag Wieers - 1.1.6-0 - Updated to release 1.1.6. * Mon Jan 26 2004 Dag Wieers - 1.1.5-0 - Updated to release 1.1.5. * Mon Dec 29 2003 Dag Wieers - 1.1.4-0 - Updated to release 1.1.4. * Fri Jun 06 2003 Dag Wieers - 1.0.3-0 - Initial package. (using DAR) keepalived-1.2.13/Makefile.in0000664000175000017500000000235312211121152015561 0ustar acassenacassen# Makefile # # Keepalived OpenSource project. # # Copyright (C) 2001-2012 Alexandre Cassen, TARFILES = AUTHOR bin ChangeLog configure configure.in CONTRIBUTORS COPYING \ doc genhash INSTALL install-sh keepalived keepalived.spec.in lib Makefile.in \ README TODO VERSION TARBALL = keepalived-@VERSION@.tar.gz all: $(MAKE) -C lib || exit 1; $(MAKE) -C keepalived $(MAKE) -C genhash @echo "" @echo "Make complete" debug: $(MAKE) -C lib || exit 1; $(MAKE) -C keepalived debug @echo "" @echo "Make complete" profile: $(MAKE) -C lib || exit 1; $(MAKE) -C keepalived profile @echo "" @echo "Make complete" clean: $(MAKE) -C lib clean $(MAKE) -C keepalived clean $(MAKE) -C genhash clean distclean: $(MAKE) -C lib distclean $(MAKE) -C keepalived distclean $(MAKE) -C genhash distclean rm -f Makefile rm -f keepalived.spec mrproper: distclean rm -f config.* uninstall: $(MAKE) -C keepalived uninstall $(MAKE) -C genhash uninstall install: $(MAKE) -C keepalived install $(MAKE) -C genhash install tarball: mrproper mkdir keepalived-@VERSION@ cp -a $(TARFILES) keepalived-@VERSION@ tar --exclude .git -czf $(TARBALL) keepalived-@VERSION@ rm -rf keepalived-@VERSION@ rpm: rpmbuild -ba keepalived.spec keepalived-1.2.13/genhash/0000775000175000017500000000000012334417517015151 5ustar acassenacassenkeepalived-1.2.13/genhash/Makefile.in0000664000175000017500000000324412211121152017176 0ustar acassenacassen# Makefile.in # # Copyright (C) 2001-2012 Alexandre Cassen, EXEC = genhash BIN = ../bin prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ mandir = @mandir@ datarootdir = @datarootdir@ CC = @CC@ STRIP = @STRIP@ INCLUDES = -I../lib CFLAGS = @CFLAGS@ @CPPFLAGS@ $(INCLUDES) \ -Wall -Wunused -Wstrict-prototypes LDFLAGS = @LIBS@ @LDFLAGS@ OBJS = main.o sock.o layer4.o http.o ssl.o LIB_OBJS = ../lib/timer.o ../lib/scheduler.o ../lib/memory.o ../lib/list.o \ ../lib/utils.o ../lib/html.o ../lib/signals.o ../lib/logger.o all: $(BIN)/$(EXEC) $(STRIP) $(BIN)/$(EXEC) @echo "" @echo "Make complete" $(BIN)/$(EXEC): $(LIB_OBJS) $(OBJS) @set -e; \ echo "Building $(BIN)/$(EXEC)" && \ $(CC) -o $(BIN)/$(EXEC) $(LIB_OBJS) $(OBJS) $(LDFLAGS) clean: rm -f core *.o distclean: clean rm -f Makefile $(BIN)/$(EXEC) uninstall: rm -f $(DESTDIR)$(bindir)/$(EXEC) rm -f $(DESTDIR)$(mandir)/man1/genhash.1 install: install -d $(DESTDIR)$(bindir) install -m 755 $(BIN)/$(EXEC) $(DESTDIR)$(bindir)/ install -d $(DESTDIR)$(mandir)/man1 install -m 644 ../doc/man/man1/genhash.1 $(DESTDIR)$(mandir)/man1 mrproper: clean distclean rm -f config.* # Code dependencies main.o: main.c main.h ../lib/utils.h sock.h ../lib/timer.h \ http.h ssl.h ../lib/scheduler.h ../lib/memory.h sock.o: sock.c sock.h ../lib/utils.h layer4.h ssl.h main.h \ ../lib/memory.h layer4.o: layer4.c layer4.h ../lib/scheduler.h ../lib/utils.h \ main.h ssl.h http.o: http.c http.h sock.h ../lib/scheduler.h ../lib/utils.h \ layer4.h main.h ../lib/html.h ../lib/timer.h ../lib/scheduler.h \ ../lib/memory.h ssl.o: ssl.c ssl.h http.h main.h ../lib/utils.h ../lib/html.h keepalived-1.2.13/genhash/ssl.h0000664000175000017500000000237612211121152016110 0ustar acassenacassen/* * Soft: Perform a GET query to a remote HTTP/HTTPS server. * Set a timer to compute global remote server response * time. * * Part: ssl.c include file. * * Version: $Id: ssl.h,v 1.1.16 2009/02/14 03:25:07 acassen Exp $ * * Authors: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _SSL_H #define _SSL_H #include /* Prototypes */ extern void init_ssl(void); extern int ssl_connect(thread_t *); extern int ssl_printerr(int); extern int ssl_send_request(SSL *, char *, int); extern int ssl_read_thread(thread_t *); #endif keepalived-1.2.13/genhash/http.h0000644000175000017500000000447712247063404016306 0ustar acassenacassen/* * Soft: Perform a GET query to a remote HTTP/HTTPS server. * Set a timer to compute global remote server response * time. * * Part: http.c include file. * * Version: $Id: http.h,v 1.1.16 2009/02/14 03:25:07 acassen Exp $ * * Authors: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _HTTP_H #define _HTTP_H /* system includes */ #include #include /* local includes */ #include "scheduler.h" #include "sock.h" /* global defs */ #define GET_BUFFER_LENGTH 2048 #define MAX_BUFFER_LENGTH 4096 #define HTTP_CNX_TIMEOUT (5 * TIMER_HZ) #define PROTO_HTTP 0x01 #define PROTO_SSL 0x02 /* GET processing command */ #define REQUEST_TEMPLATE "GET %s HTTP/1.0\r\n" \ "User-Agent: GenHash (Linux powered)\r\n" \ "Host: %s%s\r\n\r\n" #define REQUEST_TEMPLATE_IPV6 "GET %s HTTP/1.0\r\n" \ "User-Agent: GenHash (Linux powered)\r\n" \ "Host: [%s]%s\r\n\r\n" /* Output delimiters */ #define DELIM_BEGIN "-----------------------[" #define DELIM_END "]-----------------------\n" #define HTTP_HEADER_HEXA DELIM_BEGIN" HTTP Header Buffer "DELIM_END #define HTTP_HEADER_ASCII DELIM_BEGIN" HTTP Header Ascii Buffer "DELIM_END #define HTML_HEADER_HEXA DELIM_BEGIN" HTML Buffer "DELIM_END #define HTML_HASH DELIM_BEGIN" HTML hash resulting "DELIM_END #define HTML_HASH_FINAL DELIM_BEGIN" HTML hash final resulting "DELIM_END /* Globals exported */ extern const hash_t hashes[]; /* Define prototypes */ extern int epilog(thread_t *); extern int finalize(thread_t *); extern int http_process_stream(SOCK *, int); extern int http_request_thread(thread_t *); #endif keepalived-1.2.13/genhash/INSTALL0000664000175000017500000001166612211121152016171 0ustar acassenacassenNeeds ===== Before trying to compile genhash tool you need to install OpenSSL 0.9.6b (http://www.openssl.org). Installation ============ Simply 'make' & 'make install' Utilisation =========== The genhash tool give you the ability to generate MD5 digest from remote HTTP/HTTPS server connected. The global synopsis for the tool is : [user@lvs]$ genhash --help genhash v1.0.0 (18/11, 2002) Usage: genhash -s server-address -p port -u url genhash -S -s server-address -p port -u url genhash -h genhash -r Commands: Either long or short options are allowed. genhash --use-ssl -S Use SSL connection to remote server. genhash --server -s Use the specified remote server address. genhash --port -p Use the specified remote server port. genhash --url -u Use the specified remote server url. genhash --use-virtualhost -V Use the specified virtualhost in GET query. genhash --verbose -v Use verbose mode output. genhash --help -h Display this short inlined help screen. genhash --release -r Display the release number Imagine we have a remote HTTP/HTTPS server owning the IP address 192.168.200.10. We want to generate a MD5SUM over the server root url (/). To proceed, simply use : [user@lvs]$ genhash -s 192.168.200.10 -p 80 -u / -----------------------[ HTTP Header Buffer ]----------------------- 0000 48 54 54 50 2f 31 2e 31 - 20 32 30 30 20 4f 4b 0d HTTP/1.1 200 OK. 0010 0a 44 61 74 65 3a 20 57 - 65 64 2c 20 32 38 20 4e .Date: Wed, 28 N .......................................................................... -----------------------[ HTTP Header Ascii Buffer ]----------------------- HTTP/1.1 200 OK .............. -----------------------[ HTML Buffer ]----------------------- 0000 3c 21 44 4f 43 54 59 50 - 45 20 48 54 4d 4c 20 50 ..... -----------------------[ HTML MD5 final resulting ]----------------------- FF20AD2481F97B1754EF3E12ECD3A9CC => So the Hash value generated for the remote HTTP root URL is : http://192.168.200.10/ is FF20AD2481F97B1754EF3E12ECD3A9CC Genhash can generate hash values over SSL content. Using the same sample we will obtain : [user@lvs]$ genhash -S -s 192.168.200.10 -p 443 -u / -----------------------[ HTTP Header Buffer ]----------------------- 0000 48 54 54 50 2f 31 2e 31 - 20 32 30 30 20 4f 4b 0d HTTP/1.1 200 OK. 0010 0a 44 61 74 65 3a 20 57 - 65 64 2c 20 32 38 20 4e .Date: Wed, 28 N .......................................................................... -----------------------[ HTTP Header Ascii Buffer ]----------------------- HTTP/1.1 200 OK .............. -----------------------[ HTML Buffer ]----------------------- 0000 3c 21 44 4f 43 54 59 50 - 45 20 48 54 4d 4c 20 50 ..... -----------------------[ HTML MD5 final resulting ]----------------------- FF20AD2481F97B1754EF3E12ECD3A9CC => So the Hash value generated for the remote HTTP root URL is : https://192.168.200.10/ is FF20AD2481F97B1754EF3E12ECD3A9CC => The same as http since the document root is a common location for HTTP & HTTPS (in our sample). In addition with this SSL support, we have added the capability to use specific ssl private key and ssl certificate. Note that the private key need to be generated into the PEM format. In our sample we have generated the SSL file using the following openssl command lines : [user@lvs]$ openssl genrsa -des3 -out ssl.key 1024 => we use the PEM password : password (really secure :) ) [user@lvs]$ openssl req -new -key ssl.key -out ssl.csr [user@lvs]$ openssl req -x509 -key ssl.key -in ssl.csr -out ssl.crt [user@lvs]$ cat ssl.key ssl.crt > ssl.pem Then we perform a hash computation using this specific SSL file : [user@lvs]$ genhash --use-ssl \ --server=192.168.201.100 --port=443 --url=/ \ --use-private-key=ssl.pem \ --use-password=password \ --use-certificate=ssl.crt .......................................................................... -----------------------[ HTML MD5 final resulting ]----------------------- FF20AD2481F97B1754EF3E12ECD3A9CC Have fun with it ! Alexandre keepalived-1.2.13/genhash/ChangeLog0000664000175000017500000000117712211121152016706 0ustar acassenacassen2002-11-18 Alexandre Cassen * Rewrote the whole previous code to use common template libraries. 2002-01-17 Alexandre Cassen * Patched the dynamic GET request lenght allocation. 2001-11-29 Alexandre Cassen * genhash 0.4.9 released. * Rewrite the whole previous code * Jan Holmberg, and I added SSL support. * Possibility to use specific SSL certificate. * Added a command line parser using the popt library. * Added error handling support. * Review the MD5 computation. * Added a dynamic buffer allocation for remote server reply. keepalived-1.2.13/genhash/sock.h0000664000175000017500000000273312211121152016243 0ustar acassenacassen/* * Soft: Perform a GET query to a remote HTTP/HTTPS server. * Set a timer to compute global remote server response * time. * * Part: sock.c include file. * * Version: $Id: sock.h,v 1.1.16 2009/02/14 03:25:07 acassen Exp $ * * Authors: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _SOCK_H #define _SOCK_H /* system includes */ #include /* local includes */ #include "hash.h" /* Engine socket pool element structure */ typedef struct { int fd; SSL *ssl; BIO *bio; const hash_t *hash; hash_context_t context; int status; int lock; char *buffer; char *extracted; int size; int total_size; } SOCK; /* global vars exported */ extern SOCK *sock; /* Prototypes */ extern void free_sock(SOCK *); extern void init_sock(void); #endif keepalived-1.2.13/genhash/VERSION0000664000175000017500000000000612211121152016172 0ustar acassenacassen1.0.0 keepalived-1.2.13/genhash/COPYING0000664000175000017500000004307612211121152016173 0ustar acassenacassen GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy 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. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. keepalived-1.2.13/genhash/layer4.h0000644000175000017500000000333412247063404016516 0ustar acassenacassen/* * Soft: Perform a GET query to a remote HTTP/HTTPS server. * Set a timer to compute global remote server response * time. * * Part: layer4.c include file. * * Version: $Id: layer4.h,v 1.1.16 2009/02/14 03:25:07 acassen Exp $ * * Authors: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _LAYER4_H #define _LAYER4_H /* system includes */ #include #include #include #include #include #include #include /* local includes */ #include "scheduler.h" #include "main.h" enum connect_result { connect_error, connect_in_progress, connect_timeout, connect_success }; /* Prototypes defs */ extern enum connect_result tcp_connect(int fd, REQ *); extern enum connect_result tcp_socket_state(int, thread_t *, char *, uint16_t, int (*func) (thread_t *)); extern void tcp_connection_state(int, enum connect_result , thread_t *, int (*func) (thread_t *) , long); extern int tcp_connect_thread(thread_t *); #endif keepalived-1.2.13/genhash/http.c0000644000175000017500000002173712247063404016277 0ustar acassenacassen/* * Soft: Perform a GET query to a remote HTTP/HTTPS server. * Set a timer to compute global remote server response * time. * * Part: HTTP asynchronous engine. * * Version: $Id: http.c,v 1.1.16 2009/02/14 03:25:07 acassen Exp $ * * Authors: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include #include #include "memory.h" #include "http.h" #include "layer4.h" #include "main.h" #include "utils.h" #include "html.h" #include "timer.h" /* * The global design of this checker is the following : * * - All the actions are done asynchronously. * - All the actions handle timeout connection. * - All the actions handle error from low layer to upper * layers. * * The global synopsis of the inter-thread-call is : * * http_request_thread (send SSL GET request) * v * http_response_thread (initialize read stream step) * / \ * / \ * v v * http_read_thread ssl_read_thread (perform HTTP|SSL stream) * v v * ------------------------------ * finalize / epilog */ const hash_t hashes[hash_guard] = { [hash_md5] = { (hash_init_f) MD5_Init, (hash_update_f) MD5_Update, (hash_final_f) MD5_Final, MD5_DIGEST_LENGTH, "MD5", "MD5SUM", }, #ifdef FEAT_SHA1 [hash_sha1] = { (hash_init_f) SHA1_Init, (hash_update_f) SHA1_Update, (hash_final_f) SHA1_Final, SHA_DIGEST_LENGTH, "SHA1", "SHA1SUM", } #endif }; #define HASH_LENGTH(sock) ((sock)->hash->length) #define HASH_LABEL(sock) ((sock)->hash->label) #define HASH_INIT(sock) ((sock)->hash->init(&(sock)->context)) #define HASH_UPDATE(sock, buf, len) \ ((sock)->hash->update(&(sock)->context, (buf), (len))) #define HASH_FINAL(sock, digest) \ ((sock)->hash->final((digest), &(sock)->context)) /* free allocated pieces */ static void free_all(thread_t * thread) { SOCK *sock_obj = THREAD_ARG(thread); DBG("Total read size read = %d Bytes, fd:%d\n", sock_obj->total_size, sock_obj->fd); if (sock_obj->buffer) FREE(sock_obj->buffer); /* * Decrement the current global get number. * => free the reserved thread */ req->response_time = timer_tol(timer_now()); thread_add_terminate_event(thread->master); } /* Simple epilog functions. */ int epilog(thread_t * thread) { DBG("Timeout on URL : [%s]\n", req->url); free_all(thread); return 0; } /* Simple finalization function */ int finalize(thread_t * thread) { SOCK *sock_obj = THREAD_ARG(thread); unsigned char digest_length = HASH_LENGTH(sock_obj); unsigned char digest[digest_length]; int i; /* Compute final hash digest */ HASH_FINAL(sock_obj, digest); if (req->verbose) { printf("\n"); printf(HTML_HASH); dump_buffer((char *) digest, digest_length); printf(HTML_HASH_FINAL); } printf("%s = ", HASH_LABEL(sock_obj)); for (i = 0; i < digest_length; i++) printf("%02x", digest[i]); printf("\n\n"); DBG("Finalize : [%s]\n", req->url); free_all(thread); return 0; } /* Dump HTTP header */ static void http_dump_header(char *buffer, int size) { int r; dump_buffer(buffer, size); printf(HTTP_HEADER_ASCII); for (r = 0; r < size; r++) printf("%c", buffer[r]); printf("\n"); } /* Process incoming stream */ int http_process_stream(SOCK * sock_obj, int r) { sock_obj->size += r; sock_obj->total_size += r; if (!sock_obj->extracted) { if (req->verbose) printf(HTTP_HEADER_HEXA); if ((sock_obj->extracted = extract_html(sock_obj->buffer, sock_obj->size))) { if (req->verbose) http_dump_header(sock_obj->buffer + (sock_obj->size - r), (sock_obj->extracted - sock_obj->buffer) - (sock_obj->size - r)); r = sock_obj->size - (sock_obj->extracted - sock_obj->buffer); if (r) { if (req->verbose) { printf(HTML_HEADER_HEXA); dump_buffer(sock_obj->extracted, r); } memmove(sock_obj->buffer, sock_obj->extracted, r); HASH_UPDATE(sock_obj, sock_obj->buffer, r); r = 0; } sock_obj->size = r; } else { if (req->verbose) http_dump_header(sock_obj->buffer + (sock_obj->size - r), r); /* minimize buffer using no 2*CR/LF found yet */ if (sock_obj->size > 4) { memmove(sock_obj->buffer, sock_obj->buffer + sock_obj->size - 4, 4); sock_obj->size = 4; } } } else if (sock_obj->size) { if (req->verbose) dump_buffer(sock_obj->buffer, r); HASH_UPDATE(sock_obj, sock_obj->buffer, sock_obj->size); sock_obj->size = 0; } return 0; } /* Asynchronous HTTP stream reader */ int http_read_thread(thread_t * thread) { SOCK *sock_obj = THREAD_ARG(thread); int r = 0; /* Handle read timeout */ if (thread->type == THREAD_READ_TIMEOUT) return epilog(thread); /* read the HTTP stream */ r = MAX_BUFFER_LENGTH - sock_obj->size; if (r <= 0) { /* defensive check, should not occur */ fprintf(stderr, "HTTP socket buffer overflow (not consumed)\n"); r = MAX_BUFFER_LENGTH; } memset(sock_obj->buffer + sock_obj->size, 0, r); r = read(thread->u.fd, sock_obj->buffer + sock_obj->size, r); DBG(" [l:%d,fd:%d]\n", r, sock_obj->fd); if (r == -1 || r == 0) { /* -1:error , 0:EOF */ if (r == -1) { /* We have encourred a real read error */ DBG("Read error with server [%s]:%d: %s\n", req->ipaddress, ntohs(req->addr_port), strerror(errno)); return epilog(thread); } /* All the HTTP stream has been parsed */ finalize(thread); } else { /* Handle the response stream */ http_process_stream(sock_obj, r); /* * Register next http stream reader. * Register itself to not perturbe global I/O multiplexer. */ thread_add_read(thread->master, http_read_thread, sock_obj, thread->u.fd, HTTP_CNX_TIMEOUT); } return 0; } /* * Read get result from the remote web server. * Apply trigger check to this result. */ int http_response_thread(thread_t * thread) { SOCK *sock_obj = THREAD_ARG(thread); /* Handle read timeout */ if (thread->type == THREAD_READ_TIMEOUT) return epilog(thread); /* Allocate & clean the get buffer */ sock_obj->buffer = (char *) MALLOC(MAX_BUFFER_LENGTH); /* Initalize the hash context */ sock_obj->hash = &hashes[req->hash]; HASH_INIT(sock_obj); /* Register asynchronous http/ssl read thread */ if (req->ssl) thread_add_read(thread->master, ssl_read_thread, sock_obj, thread->u.fd, HTTP_CNX_TIMEOUT); else thread_add_read(thread->master, http_read_thread, sock_obj, thread->u.fd, HTTP_CNX_TIMEOUT); return 0; } /* remote Web server is connected, send it the get url query. */ int http_request_thread(thread_t * thread) { SOCK *sock_obj = THREAD_ARG(thread); char *str_request; char *request_host; char *request_host_port; int ret = 0; /* Handle read timeout */ if (thread->type == THREAD_WRITE_TIMEOUT) return epilog(thread); /* Allocate & clean the GET string */ str_request = (char *) MALLOC(GET_BUFFER_LENGTH); memset(str_request, 0, GET_BUFFER_LENGTH); if (req->vhost) { /* If vhost was defined we don't need to override it's port */ request_host = req->vhost; request_host_port = (char*) MALLOC(1); *request_host_port = 0; } else { request_host = req->ipaddress; /* Allocate a buffer for the port string ( ":" [0-9][0-9][0-9][0-9][0-9] "\0" ) */ request_host_port = (char*) MALLOC(7); snprintf(request_host_port, 7, ":%d", ntohs(req->addr_port)); } if(req->dst){ if(req->dst->ai_family == AF_INET6 && !req->vhost) { snprintf(str_request, GET_BUFFER_LENGTH, REQUEST_TEMPLATE_IPV6, req->url, request_host, request_host_port); } else { snprintf(str_request, GET_BUFFER_LENGTH, REQUEST_TEMPLATE, req->url, request_host, request_host_port); } } else { snprintf(str_request, GET_BUFFER_LENGTH, REQUEST_TEMPLATE, req->url, request_host, request_host_port); } FREE(request_host_port); /* Send the GET request to remote Web server */ DBG("Sending GET request [%s] on fd:%d\n", req->url, sock_obj->fd); if (req->ssl) ret = ssl_send_request(sock_obj->ssl, str_request, strlen(str_request)); else ret = (send(sock_obj->fd, str_request, strlen(str_request), 0) != -1) ? 1 : 0; FREE(str_request); if (!ret) { fprintf(stderr, "Cannot send get request to [%s]:%d.\n", req->ipaddress, ntohs(req->addr_port)); return epilog(thread); } /* Register read timeouted thread */ thread_add_read(thread->master, http_response_thread, sock_obj, sock_obj->fd, HTTP_CNX_TIMEOUT); return 1; } keepalived-1.2.13/genhash/main.c0000644000175000017500000001552612247331013016235 0ustar acassenacassen/* * Soft: Perform a GET query to a remote HTTP/HTTPS server. * Set a timer to compute global remote server response * time. * * Part: Main entry point. * * Version: $Id: main.c,v 1.1.16 2009/02/14 03:25:07 acassen Exp $ * * Authors: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include #include #include #include "main.h" #include "utils.h" #include "signals.h" #include #include #include #include #include /* global var */ REQ *req = NULL; /* Terminate handler */ void sigend(void *v, int sig) { /* register the terminate thread */ thread_add_terminate_event(master); } /* Initialize signal handler */ void signal_init(void) { signal_handler_init(); signal_set(SIGHUP, sigend, NULL); signal_set(SIGINT, sigend, NULL); signal_set(SIGTERM, sigend, NULL); signal_ignore(SIGPIPE); } /* Usage function */ static void usage(const char *prog) { enum feat_hashes i; fprintf(stderr, VERSION_STRING); fprintf(stderr, "Usage:\n" " %s -s server-address -p port -u url\n" " %s -S -s server-address -p port -u url\n" " %s -h\n" " %s -r\n\n", prog, prog, prog, prog); fprintf(stderr, "Commands:\n" "Either long or short options are allowed.\n" " %s --use-ssl -S Use SSL connection to remote server.\n" " %s --server -s Use the specified remote server address.\n" " %s --port -p Use the specified remote server port.\n" " %s --url -u Use the specified remote server url.\n" " %s --use-virtualhost -V Use the specified virtualhost in GET query.\n" " %s --hash -H Use the specified hash algorithm.\n" " %s --verbose -v Use verbose mode output.\n" " %s --help -h Display this short inlined help screen.\n" " %s --release -r Display the release number\n", prog, prog, prog, prog, prog, prog, prog, prog, prog); fprintf(stderr, "\nSupported hash algorithms:\n"); for (i = hash_first; i < hash_guard; i++) fprintf(stderr, " %s%s\n", hashes[i].id, i == hash_default ? " (default)": ""); } /* Command line parser */ static int parse_cmdline(int argc, char **argv, REQ * req_obj) { int c; enum feat_hashes i; struct addrinfo hint, *res = NULL; int ret; void *ptr; memset(&hint, '\0', sizeof hint); hint.ai_family = PF_UNSPEC; hint.ai_flags = AI_NUMERICHOST; struct option long_options[] = { {"release", no_argument, 0, 'r'}, {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'}, {"use-ssl", no_argument, 0, 'S'}, {"server", required_argument, 0, 's'}, {"hash", required_argument, 0, 'H'}, {"use-virtualhost", required_argument, 0, 'V'}, {"port", required_argument, 0, 'p'}, {"url", required_argument, 0, 'u'}, {0, 0, 0, 0} }; /* Parse the command line arguments */ while ((c = getopt_long (argc, argv, "rhvSs:H:V:p:u:", long_options, NULL)) != EOF) { switch (c) { case 'r': fprintf(stderr, VERSION_STRING); break; case 'h': usage(argv[0]); break; case 'v': req_obj->verbose = 1; break; case 'S': req_obj->ssl = 1; break; case 's': if ((ret = getaddrinfo(optarg, NULL, &hint, &res)) != 0){ fprintf(stderr, "server should be an IP, not %s\n", optarg); return CMD_LINE_ERROR; } else { if(res->ai_family == AF_INET) { req_obj->dst = res; ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr; inet_ntop (res->ai_family, ptr, req_obj->ipaddress, INET6_ADDRSTRLEN); } else if (res->ai_family == AF_INET6) { req_obj->dst = res; ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; inet_ntop (res->ai_family, ptr, req_obj->ipaddress, INET6_ADDRSTRLEN); } else { fprintf(stderr, "server should be an IP, not %s\n", optarg); return CMD_LINE_ERROR; } } break; case 'H': for (i = hash_first; i < hash_guard; i++) if (!strcasecmp(optarg, hashes[i].id)) { req_obj->hash = i; break; } if (i == hash_guard) { fprintf(stderr, "unknown hash algoritm: %s\n", optarg); return CMD_LINE_ERROR; } break; case 'V': req_obj->vhost = optarg; break; case 'p': req_obj->addr_port = htons(atoi(optarg)); break; case 'u': req_obj->url = optarg; break; default: usage(argv[0]); return CMD_LINE_ERROR; } } /* check unexpected arguments */ if (optind < argc) { fprintf(stderr, "Unexpected argument(s): "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); return CMD_LINE_ERROR; } return CMD_LINE_SUCCESS; } int main(int argc, char **argv) { thread_t thread; char *url_default = malloc(2); url_default[0] = '/'; url_default[1] = '\0'; /* Allocate the room */ req = (REQ *) MALLOC(sizeof (REQ)); /* Preset (potentially) non-zero defaults */ req->hash = hash_default; /* Command line parser */ if (!parse_cmdline(argc, argv, req)) { FREE(url_default); FREE(req); exit(0); } /* Check minimum configuration need */ if (!req->dst && !req->addr_port && !req->url) { FREE(url_default); freeaddrinfo(req->dst); FREE(req); exit(0); } if(!req->url){ req->url = url_default; } /* Init the reference timer */ req->ref_time = timer_tol(timer_now()); DBG("Reference timer = %lu\n", req->ref_time); /* Init SSL context */ init_ssl(); /* Signal handling initialization */ signal_init(); /* Create the master thread */ master = thread_make_master(); /* Register the GET request */ init_sock(); /* * Processing the master thread queues, * return and execute one ready thread. * Run until error, used for debuging only. * Note that not calling launch_scheduler() does * not activate SIGCHLD handling, however, this * is no issue here. */ while (thread_fetch(master, &thread)) thread_call(&thread); /* Finalize output informations */ if (req->verbose) printf("Global response time for [%s] =%lu\n", req->url, req->response_time - req->ref_time); /* exit cleanly */ FREE(url_default); SSL_CTX_free(req->ctx); free_sock(sock); freeaddrinfo(req->dst); FREE(req); exit(0); } keepalived-1.2.13/genhash/README0000664000175000017500000000102512211121152016004 0ustar acassenacassenThe main goal of the keepalived project is to add a strong & robust keepalive facility to the Linux Virtual Server project. It implements a multilayer TCP/IP stack checks. Keepalived implements a framework based on three family checks : Layer3, Layer4 & Layer5. This framework gives the daemon the ability of checking a LVS server pool states. Keepalived can be sumarize as a LVS driving daemon. To generate MD5SUM digest the this tool (genhash) is used. Keepalived is free software. See the file COPYING for copying conditions. keepalived-1.2.13/genhash/layer4.c0000644000175000017500000001533112247063404016511 0ustar acassenacassen/* * Soft: Perform a GET query to a remote HTTP/HTTPS server. * Set a timer to compute global remote server response * time. * * Part: Layer4 asynchronous primitives. * * Version: $Id: layer4.c,v 1.1.16 2009/02/14 03:25:07 acassen Exp $ * * Authors: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "layer4.h" #include "utils.h" #include "main.h" #include "sock.h" #include "http.h" #include "ssl.h" enum connect_result tcp_connect(int fd, REQ * req_obj) { struct linger li = { 0 }; int long_inet; struct sockaddr_in adr_serv; struct sockaddr_in6 adr_serv6; int ret; int val; /* free the tcp port after closing the socket descriptor */ li.l_onoff = 1; li.l_linger = 0; setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof (struct linger)); /* Make socket non-block. */ val = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, val | O_NONBLOCK); if(req_obj->dst){ if(req_obj->dst->ai_family == AF_INET6) { long_inet = sizeof (struct sockaddr_in6); memset(&adr_serv6, 0, long_inet); adr_serv6.sin6_family = req_obj->dst->ai_family; adr_serv6.sin6_port = req_obj->addr_port; inet_pton(AF_INET6, req_obj->ipaddress, &adr_serv6.sin6_addr); /* Call connect function. */ ret = connect(fd, (struct sockaddr *) &adr_serv6, long_inet); } else { long_inet = sizeof (struct sockaddr_in); memset(&adr_serv, 0, long_inet); adr_serv.sin_family = req_obj->dst->ai_family; adr_serv.sin_port = req_obj->addr_port; inet_pton(AF_INET, req_obj->ipaddress, &adr_serv.sin_addr); /* Call connect function. */ ret = connect(fd, (struct sockaddr *) &adr_serv, long_inet); } } else { long_inet = sizeof (struct sockaddr_in); memset(&adr_serv, 0, long_inet); adr_serv.sin_family = AF_INET; adr_serv.sin_port = req_obj->addr_port; inet_pton(AF_INET, req_obj->ipaddress, &adr_serv.sin_addr); /* Call connect function. */ ret = connect(fd, (struct sockaddr *) &adr_serv, long_inet); } /* Immediate success */ if (ret == 0) { fcntl(fd, F_SETFL, val); return connect_success; } /* If connect is in progress then return 1 else it's real error. */ if (ret < 0) { if (errno != EINPROGRESS) return connect_error; } /* restore previous fd args */ fcntl(fd, F_SETFL, val); return connect_in_progress; } enum connect_result tcp_socket_state(int fd, thread_t * thread, char *ipaddress, uint16_t addr_port, int (*func) (thread_t *)) { int status; socklen_t slen; int ret = 0; timeval_t timer_min; /* Handle connection timeout */ if (thread->type == THREAD_WRITE_TIMEOUT) { DBG("TCP connection timeout to [%s]:%d.\n", ipaddress, ntohs(addr_port)); close(thread->u.fd); return connect_timeout; } /* Check file descriptor */ slen = sizeof (status); if (getsockopt (thread->u.fd, SOL_SOCKET, SO_ERROR, (void *) &status, &slen) < 0) ret = errno; /* Connection failed !!! */ if (ret) { DBG("TCP connection failed to [%s]:%d.\n", ipaddress, ntohs(addr_port)); close(thread->u.fd); return connect_error; } /* If status = 0, TCP connection to remote host is established. * Otherwise register checker thread to handle connection in progress, * and other error code until connection is established. * Recompute the write timeout (or pending connection). */ if (status != 0) { DBG("TCP connection to [%s]:%d still IN_PROGRESS.\n", ipaddress, ntohs(addr_port)); timer_min = timer_sub_now(thread->sands); thread_add_write(thread->master, func, THREAD_ARG(thread) , thread->u.fd, timer_long(timer_min)); return connect_in_progress; } return connect_success; } void tcp_connection_state(int fd, enum connect_result status, thread_t * thread, int (*func) (thread_t *) , long timeout) { switch (status) { case connect_error: close(fd); break; case connect_success: thread_add_write(thread->master, func, THREAD_ARG(thread), fd, timeout); break; /* Checking non-blocking connect, we wait until socket is writable */ case connect_in_progress: thread_add_write(thread->master, func, THREAD_ARG(thread), fd, timeout); break; default: break; } } int tcp_check_thread(thread_t * thread) { SOCK *sock_obj = THREAD_ARG(thread); int ret = 1; sock_obj->status = tcp_socket_state(thread->u.fd, thread, req->ipaddress, req->addr_port, tcp_check_thread); switch (sock_obj->status) { case connect_error: DBG("Error connecting server [%s]:%d.\n", req->ipaddress, ntohs(req->addr_port)); thread_add_terminate_event(thread->master); return -1; break; case connect_timeout: DBG("Timeout connecting server [%s]:%d.\n", req->ipaddress, ntohs(req->addr_port)); thread_add_terminate_event(thread->master); return -1; break; case connect_success:{ if (req->ssl) ret = ssl_connect(thread); if (ret) { /* Remote WEB server is connected. * Unlock eventual locked socket. */ sock_obj->lock = 0; thread_add_event(thread->master, http_request_thread, sock_obj, 0); } else { DBG("Connection trouble to: [%s]:%d.\n", req->ipaddress, ntohs(req->addr_port)); if (req->ssl) ssl_printerr(SSL_get_error (sock_obj->ssl, ret)); sock_obj->status = connect_error; return -1; } } break; } return 1; } int tcp_connect_thread(thread_t * thread) { SOCK *sock_obj = THREAD_ARG(thread); if(req->dst){ if(req->dst->ai_family == AF_INET6) { if ((sock_obj->fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) == -1) { DBG("WEB connection fail to create socket.\n"); return 0; } } else { if ((sock_obj->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { DBG("WEB connection fail to create socket.\n"); return 0; } } } else { if ((sock_obj->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { DBG("WEB connection fail to create socket.\n"); return 0; } } sock->status = tcp_connect(sock_obj->fd, req); /* handle tcp connection status & register check worker thread */ tcp_connection_state(sock_obj->fd, sock_obj->status, thread, tcp_check_thread, HTTP_CNX_TIMEOUT); return 0; } keepalived-1.2.13/genhash/main.h0000644000175000017500000000451312247063404016242 0ustar acassenacassen/* * Soft: Perform a GET query to a remote HTTP/HTTPS server. * Set a timer to compute global remote server response * time. * * Part: main.c include file. * * Version: $Id: main.h,v 1.1.16 2009/02/14 03:25:07 acassen Exp $ * * Authors: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _MAIN_H #define _MAIN_H /* global includes */ #include #include #include #include #include #include #include #include #include #include /* local includes */ #include "memory.h" #include "timer.h" #include "http.h" #include "ssl.h" #include "list.h" #include "sock.h" /* Build version */ #define PROG "genhash" #define VERSION_CODE 0x010000 #define DATE_CODE 0x15070d #define GETMETER_VERSION(version) \ (version >> 16) & 0xFF, \ (version >> 8) & 0xFF, \ version & 0xFF #define VERSION_STRING PROG" v%d.%d.%d (%.2d/%.2d, 20%.2d)\n", \ GETMETER_VERSION(VERSION_CODE), \ GETMETER_VERSION(DATE_CODE) /* HTTP/HTTPS request structure */ typedef struct { struct addrinfo *dst; char ipaddress[INET6_ADDRSTRLEN]; uint16_t addr_port; char *url; char *vhost; int verbose; int ssl; SSL_CTX *ctx; SSL_METHOD *meth; enum feat_hashes hash; unsigned long ref_time; unsigned long response_time; } REQ; /* Global variables */ extern thread_master_t *master; extern REQ *req; /* Cmd line arguments */ /* Data buffer length description */ #define BUFSIZE 1024 /* Command line error handling */ #define CMD_LINE_ERROR 0 #define CMD_LINE_SUCCESS 1 #endif keepalived-1.2.13/genhash/hash.h0000664000175000017500000000361012211121152016222 0ustar acassenacassen/* * Soft: Perform a GET query to a remote HTTP/HTTPS server. * Set a timer to compute global remote server response * time. * * Part: Hash-related declarations (to break circular deps). * * Version: hash.h 2013/07/22 * * Authors: Jan Pokorny, * * 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. * * 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. * * Copyright 2013 Red Hat, Inc. */ #ifndef _HASH_H #define _HASH_H #include #ifdef FEAT_SHA1 # include #endif /* available hashes enumeration */ enum feat_hashes { hash_first, hash_md5 = hash_first, #ifdef FEAT_SHA1 hash_sha1, #endif hash_guard, hash_default = hash_md5, }; typedef union { MD5_CTX md5; #ifdef FEAT_SHA1 SHA_CTX sha; #endif /* this is due to poor C standard/draft wording (wrapped): https://groups.google.com/forum/#!msg/comp.lang.c/ 1kQMGXhgn4I/0VBEYG_ji44J */ char *dummy; } hash_context_t; typedef void (*hash_init_f)(hash_context_t *); typedef void (*hash_update_f)(hash_context_t *, const void *, unsigned long); typedef void (*hash_final_f)(unsigned char *, hash_context_t *); typedef struct { hash_init_f init; hash_update_f update; hash_final_f final; unsigned char length; /* length of the digest */ const char *id; /* command-line handing + help*/ const char *label; /* final output */ } hash_t; #endif keepalived-1.2.13/genhash/AUTHOR0000664000175000017500000000004712211121152016054 0ustar acassenacassenAlexandre Cassen, keepalived-1.2.13/genhash/sock.c0000664000175000017500000000327012211121152016233 0ustar acassenacassen/* * Soft: Perform a GET query to a remote HTTP/HTTPS server. * Set a timer to compute global remote server response * time. * * Part: Socket pool utility functions. * * Version: $Id: sock.c,v 1.1.16 2009/02/14 03:25:07 acassen Exp $ * * Authors: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include #include "memory.h" #include "utils.h" #include "list.h" #include "sock.h" #include "layer4.h" #include "ssl.h" #include "main.h" /* global var */ SOCK *sock = NULL; /* Close the descriptor */ static void close_sock(SOCK * sock_obj) { if (sock_obj->ssl) { SSL_shutdown(sock_obj->ssl); SSL_free(sock_obj->ssl); } close(sock_obj->fd); } /* Destroy the socket handler */ void free_sock(SOCK * sock_obj) { DBG("Freeing fd:%d\n", sock_obj->fd); close_sock(sock_obj); FREE(sock_obj); } /* Init socket handler */ void init_sock(void) { sock = (SOCK *) MALLOC(sizeof (SOCK)); memset(sock, 0, sizeof (SOCK)); thread_add_event(master, tcp_connect_thread, sock, 0); } keepalived-1.2.13/genhash/ssl.c0000664000175000017500000001175312211121152016102 0ustar acassenacassen/* * Soft: Perform a GET query to a remote HTTP/HTTPS server. * Set a timer to compute global remote server response * time. * * Part: SSL engine. 'Semi' asyncrhonous stream handling. * * Version: $Id: ssl.c,v 1.1.16 2009/02/14 03:25:07 acassen Exp $ * * Authors: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include #include "main.h" #include "sock.h" #include "http.h" #include "ssl.h" #include "utils.h" #include "html.h" /* extern variables */ extern REQ *req; /* * Initialize the SSL context, with or without specific * configuration files. */ static BIO *bio_err = 0; void init_ssl(void) { /* Library initialization */ SSL_library_init(); SSL_load_error_strings(); bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); /* Initialize SSL context for SSL v2/3 */ req->meth = (SSL_METHOD *) SSLv23_method(); req->ctx = SSL_CTX_new(req->meth); #if (OPENSSL_VERSION_NUMBER < 0x00905100L) SSL_CTX_set_verify_depth(req->ctx, 1); #endif } /* Display SSL error to readable string */ int ssl_printerr(int err) { unsigned long extended_error = 0; char *ssl_strerr; switch (err) { case SSL_ERROR_ZERO_RETURN: fprintf(stderr, " SSL error: (zero return)\n"); break; case SSL_ERROR_WANT_READ: fprintf(stderr, " SSL error: (read error)\n"); break; case SSL_ERROR_WANT_WRITE: fprintf(stderr, " SSL error: (write error)\n"); break; case SSL_ERROR_WANT_CONNECT: fprintf(stderr, " SSL error: (connect error)\n"); break; case SSL_ERROR_WANT_X509_LOOKUP: fprintf(stderr, " SSL error: (X509 lookup error)\n"); break; case SSL_ERROR_SYSCALL: fprintf(stderr, " SSL error: (syscall error)\n"); break; case SSL_ERROR_SSL:{ ssl_strerr = (char *) MALLOC(500); extended_error = ERR_get_error(); ERR_error_string(extended_error, ssl_strerr); fprintf(stderr, " SSL error: (%s)\n", ssl_strerr); FREE(ssl_strerr); break; } } return 0; } int ssl_connect(thread_t * thread) { SOCK *sock_obj = THREAD_ARG(thread); int ret; sock_obj->ssl = SSL_new(req->ctx); sock_obj->bio = BIO_new_socket(sock_obj->fd, BIO_NOCLOSE); BIO_set_nbio(sock_obj->bio, 1); /* Set the Non-Blocking flag */ SSL_set_bio(sock_obj->ssl, sock_obj->bio, sock_obj->bio); ret = SSL_connect(sock_obj->ssl); DBG(" SSL_connect return code = %d on fd:%d\n", ret, thread->u.fd); ssl_printerr(SSL_get_error(sock_obj->ssl, ret)); return (ret > 0) ? 1 : 0; } int ssl_send_request(SSL * ssl, char *str_request, int request_len) { int err, r = 0; while (1) { err = 1; r = SSL_write(ssl, str_request, request_len); if (SSL_ERROR_NONE != SSL_get_error(ssl, r)) break; err++; if (request_len != r) break; err++; break; } return (err == 3) ? 1 : 0; } /* Asynchronous SSL stream reader */ int ssl_read_thread(thread_t * thread) { SOCK *sock_obj = THREAD_ARG(thread); int r = 0; int error; /* Handle read timeout */ if (thread->type == THREAD_READ_TIMEOUT) return epilog(thread); /* * The design implemented here is a workaround for use * with OpenSSL. This goto loop is a 'read until not * end of stream'. But this break a little our global * I/O multiplexer thread framework because it enter * a synchronous read process for each GET reply. * Sound a little nasty !. * * Why OpenSSL doesn t handle underlying fd. This * break the I/O (select()) approach !... * If you read this and know the answer, please reply * I am probably missing something... :) * My test show that sometime it return from select, * and sometime not... */ read_stream: /* read the SSL stream */ r = MAX_BUFFER_LENGTH - sock_obj->size; if (r <= 0) { /* defensive check, should not occur */ fprintf(stderr, "SSL socket buffer overflow (not consumed)\n"); r = MAX_BUFFER_LENGTH; } memset(sock_obj->buffer + sock_obj->size, 0, r); r = SSL_read(sock_obj->ssl, sock_obj->buffer + sock_obj->size, r); error = SSL_get_error(sock_obj->ssl, r); DBG(" [l:%d,fd:%d]\n", r, sock_obj->fd); if (error) { /* All the SSL streal has been parsed */ /* Handle response stream */ if (error != SSL_ERROR_NONE) return finalize(thread); } else if (r > 0 && error == 0) { /* Handle the response stream */ http_process_stream(sock_obj, r); /* * Register next ssl stream reader. * Register itself to not perturbe global I/O multiplexer. */ goto read_stream; } return 0; } keepalived-1.2.13/INSTALL0000664000175000017500000000310112211121152014535 0ustar acassenacassenKernel needing ============== Compile a kernel with the following options : Kernel/User netlink socket Network firewalls (for Kernel 2.2) LinuxVirtualServer Keepalived support all LVS code : including IPVS code for kernel 2.2 and kernel 2.4 Libraries dependency ==================== In order to compile Keepalived needs the following libraries : * OpenSSL, * popt Installation ============ 1. uncompress the tarball 2. cd into the directory 3. './configure' 4. 'make' 5. 'make install'. This will install keepalived on your system, binaries and configuration file : * keepalived : The keepalived daemon program. * genhash : The MD5 url digest generator. You need it to configure HTTP GET check and SSL GET check in order to compute MD5SUM digest etalon. * /etc/keepalived/keepalived.conf 6. link keepalived.init into your runlevel directory. On redhat systems : ln -s /etc/rc.d/init.d/keepalived.init /etc/rc.d/rc3.d/S99keepalived By default configure script use /usr/local as base directory. You can change this value to your own by passing --prefix value to configure script eg: './configure --prefix=/usr/' Configuration ============= Just take a look to the /etc/keepalived/keepalived.conf file installed. It will give you all the informations needed. If you want more informations considering keepalived, please refer to the keepalived homepage into the documentation section. http://www.keepalived.org Have fun with it ! Alexandre, keepalived-1.2.13/ChangeLog0000664000175000017500000041052312334416605015310 0ustar acassenacassen2014-05-13 Alexandre Cassen * keepalived-1.2.13 released. * vrrp : Use the standard unsigned int types. This fixes building with musl libc, which does not expose the internal __uint* defines. (Natanael Copa) * check : Fix template issue in IPv6 host header. (Jan Hugo Prins) * ipvs : ipvs_syncd_cmd uses memset() to zero the daemonrule buffer before populating it and sending it up. daemonrule is malloc()ed by ipvs_start(). ipvs_start() can bail early if it can't communicate with ipvs. Neither place which call ipvs_start() check the return value, allowing them to walk straight into a NULL pointer deref. (jsgh) * check : Without inhibit_on_failure on a real_server, when the server is marked down existing TCP connections to it are simply blackholed. Hence inhibit_on_failure: by setting the weight to zero no new connections are sent to that server, but because the server isn't completely removed from the table existing connections are allowed to continue. The same problem exists with sorry_server. When a real_server comes back up the sorry_server is removed from the pool and existing connections are blackholed. Instead of continued service, which may usually be a fast response indicating overload, the client must engage in a lengthy wait for the connection to time out. It would be better in many cases to allow the sorry_server connections to complete naturally. Luckily the code is structured well enough that all is required to get this behaviour is to set the inhibit member of the sorry_server structure, which is mostly just a change to the config file parser. (jsgh) * check : unify logging of RS and VS. This fixes the bug of displaying a FWM service as [x.x.x.x]:0, where x.x.x.x is the first RS of that service. (Alexey Andriyanov) * check : unify connection options among checkers. All the remote checkers (TCP, HTTP/SSL, SMTP) now have the same set of connection options: . connect_ip (new to TCP, HTTP) . connect_port . bindto . bind_port (new) . connect_timeout (new to SMTP) All of them are optional with reasonable defaults. The patch is designed for simplicity in adding a new option. Since the connect_ip could be inequal to the RS address and, worse, the same for all RSes, the endpoint is now logged as [RS]:rport, not the [connect_ip]:connect_port. (Alexey Andriyanov) * check : fwmark connection option. (Alexey Andriyanov) * check : make SO_MARK a compile-time option. (Alexey Andriyanov) * check : documentation for generic connection opts. (Alexey Andriyanov) * check : random delay before doing the first check. every RS check is registered with a random delay between 0 and vs->delay_loop seconds. It helps avoiding multiple simultaneous checks to the same RS server. (Alexey Andriyanov) * vrrp : Fix sync of interface status flag when using VMAC interface. There is a chance that the VMAC interface status flags (up/down) could be different from the base interface flags. This patch will only change the VMAC interface status flags when the base interface is changed. (Jonas Johansson) * vrrp : Let only base interface change the VMAC interface status flags. The interface status flags for a VMAC interface shall only be changed by the base interface, never by reading the actual VMAC interface flags. (Jonas Johansson) * vrrp : Fix initial interface status flag value for VMAC interface. In commit a05a503, "vrrp: Fix sync of interface status flag when using VMAC interface", no inital value for the VMAC interface status flag was set. Due to that the VMAC interface flags shall follow the base interface, the base interface status flags value shall be copied to the VMAC interface status flags after the VMAC interface has been created. (Jonas Johansson) * vrrp : Proper restore of VMAC interface properties on SIGHUP. On SIGHUP the VMAC flag and base ifindex for a VMAC interface was lost. (Jonas Johansson) * vrrp : Revert "Honor preempt_delay setting on startup.". This commit resulted in two individual bugs: 1) A keepalived instance coming on-line would not transition to MASTER state until the preempt_delay duration had passed, even though there was no already existing VRRP speaker in MASTER state on the link. In other words, it changed the semantics of preempt_delay from a delay that only took place before *preemption* of another VRRP speaker, to a delay that unconditionally took place after Keepalived came online. The keepalived.conf manual page has always documented the former meaning, which is also IMHO the only one that you would intuitively expect. 2) The preempt_delay was applied when a Keepalived process was reloading its configuration following the recipt of SIGHUP. If the Keepalived instance was in MASTER state before the reload, it would cease transmitting VRRP hellos for the duration of preempt_delay, but *not* actually remove the virtual addresses from the network interfaces. This in turn resulted in any backup VRRP speakers on the links transition to the MASTER state while preempt_delay was still in effect on the original MASTER that was reloaded, thus creating a service-impacting split-brain scenario where the virtual addresses are present and active on multiple VRRP speakers simultaneously. (Tore Anderson) * vrrp : fix ip_address comparison. Extend IP_ISEQ() macro to take care of NULL addresses. This issue end on SEGV while using virtual_route. thanks to Tore Anderson for reporting. * vrrp : fix double close issue (DROP_MEMBERSHIP & netlink channel). This is a old pending 'bug', not arming at all but just frustrating to see again and again this log message : "cant do IP_DROP_MEMBERSHIP errno=Bad file descriptor (9)" What the hell ! it was due to a double close during reload & stop procedure. VRRP fd are stored in a socket pool and use the I/O MUX to handle VRRP traffic. While reloading or stopping the daemon the I/O MUX was released first and secondly socket pool. The issue spotted here, in thread_destroy_master() all pending thread are canceled and read/write fds related are close(). Well OK a close on a mcast socket perform kernel side the DROP_MEMBERSHIP when needed, but it is much more clean to perform proper operations userspace ! This patch sequencely cancel pending thread, release socket pool and finally destroy master thread. Same 'issue' appear in netlink channel. 2014-02-08 Alexandre Cassen * keepalived-1.2.12 released. * lib: Fix reallocation issue introduced in last merge. 2014-01-28 Alexandre Cassen * keepalived-1.2.11 released. * ipvs: make nlerr2syserr libnl dependent. nlerr2syserr() is only used when libnl is present... simply reflect this in libipvs. * Fix libnl/libnl-3 logic in configure script. This patch causes the configure script to prefer libnl-3 over libnl(1). The configure script will first check for libnl-3 and libnl-genl-3. If both are found, use them. If not, check for libnl(1). This is useful when building on systems that have both libnl-3 and libnl(1) installed. It also fixes some redundant libraries in LIBS. * libipvs: libnl-3 include fix. * lib: extend command lib string parser. Extend cmd_make_strvec to support quoted string as a single slot and commented string at the end of parsed string. * lib: cosmetics at command.c. Extend command framework to support logger and remove some dead code. some cosmetics too. * lib: extend vty to support logger. * autoconf: better libnl3 detection. * Fix memory allocation in parser. The set_value function was incorrectly using sizeof (char *) when allocation and reallocating memory. * Fix memory allocation for MD5 digest. The vrrp_in_chk_ipsecah and vrrp_build_ipsecah functions were incorrectly using sizeof (unsigned char *) when allocating memory for the MD5 digest. * Fix memory leak in vty_read_config. If vty_use_backup_config returns NULL, free any memory that has been allocated before returning. * Fix memory leak in check_include. The check_include function should always free the allocated strvec. * Check content length before allocating memory. Since extract_content_length should return 0 if CONTENT_LENGTH is not found in the buffer, this check should be done before allocating memory. This avoids unnecessary malloc/free calls and fixes a potential memory leak. * Free memory if realloc fails in vty_out. If realloc returns NULL, free the original memory before returning. * Remove redundant close from vty_use_backup_config. The sav file descriptor is closed after read, so there is no need to close it again is chmod operation fails. * Remove unnecessary netlink rtattr structures. Both netlink_link_setmode and netlink_link_add_vmac have rtattr structures that are no needed. The addattr_l function will handle adding the rtattr to the message. Also, this patch removes incorrect void pointer arithmetic when setting rta_len. * vrrp: dont try to leave mcast group in unicast mode. * vrrp: Release and refresh properly fd hash index. Rehashing into the same loop as releasing is not really the best idea... Reworked a little previous patch to properly release hash entries related to the same instance and then hash it back on new fd. * vrrp: use configuration mcast group for leave message. * vrrp: dont try to load ip_vs module when not needed. 2014-01-02 Alexandre Cassen * keepalived-1.2.10 released. * Jonas Johansson removed unused option character in getopt optstring. * vrrp: disable TTL sanity check for unicast use-case. In order to protect against any packet injection, VRRP provides sanity check over IP header TTL. This TTL MUST be equal to 255 and means both sender and receiver are attached on the same ethernet segment. Now with unicast extension this protection MUST be disabled since VRRP adverts will mostly traverse different network segments. !!! WARNING !!! When using VRRP in unicast use-case in order to protect against any packet injection the best practice is to use IPSEC-AH auth method otherwise you are exposed to potential attackers ! * Christian Albrecht fixed minor typo in man page * Pim van den Berg work on libipvs-2.6 to sync with libipvs from ipvsadm 1.27 * Pim van den Berg work add support to libnk >= 3. This address following considerations : http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=688164 http://article.gmane.org/gmane.linux.keepalived.devel/3522 * Pim van den Berg extended libipvs adding nlerr2syserr function to translate libnl 3 errors to sys errors. In libnl 3 the return codes have changed. nlerr2syserr translates the libnl 3 errors to sys errors. * ipvs: if libnl-3 is installed then check for libnl-gen-3. It is mandatory to use generic netlink facilities in new libipvs. This test is just here to ensure every needed libs are installed ! * Frank Baalbergen (I suppose github frankbb is you ?) fix http checker. literal ipv6 addresses should be enclosed by brackets. * vrrp: Frank Baalbergen add check on IFA_F_NODAD support. * vrrp: fix unicast handling address selection. SjonHortensius reported issue while testing unicast_peer. It wouldn't work without adding the native_ipv6 flag. Removed this dependency ! since it not correlated with VRRP protocol version used. * vrrp: extend ip parser to support default and default6. When you are using virtual_routes you may want to use default or default6 while configuring routes. Extended parser accordingly ! * vrrp: take care of label while comparing IP addresses. Label was not taken into account while comparing 2 IP addresses, this can lead to a non deletion while stopping daemon and some configuration changes have been done while deamon running. This issue was reported by Stepan Rogov. * vrrp: fix/extend gratuitous ARP handling. multiple people reported issues where MASTER didnt recover properly after outage due to no gratuitous ARP sent. VRRP is a protocol designed to be used between node plugged on the same layer2 in order to guarantee link failure is directly linked to a protocol FSM handling (FAULT transition). With current virtualization env quite every think can be virtualized from host (VM) to network (vswitch). In some cases those virtualized env offer a virtualized layer2 on which VRRP is plugged and sometime forwarding or routing over this virtual path can be broken. I extended gratuitous ARP handling in 2 ways : 1) When a MASTER receive a higher prio advert it sends a last advert before transiting to BACKUP state. The immediate effect at remote MASTER side is to sollicite a gratuitous ARP broadcast. 2) Add an optional support to periodic gratuitous ARP sending while in MASTER state. By default it is disabled but one can activate this feature by configuring keyword "garp_master_refresh" in seconds in vrrp_instance block (refer to keepalived.conf.SYNOPSIS). * Frank Baalbergen fixed genhash. genhash can throw a segmentation fault when not providing an argument * Frank Baalbergen extended genhash code to support IPv6 * Frank Baalbergen extended genhash code to make url default value /, same as curl/wget * Frank Baalbergen extended genhash code to only use default url when url is empty * vrrp: Create configuration alias for unicast_src_ip keyword. Add a new keyword more generic to specify VRRP packet source IP address. This new keyword is "unicast_src_ip" and have exactly the same scope as "mcast_src_ip". * vrrp: unicast_peer addresses and VRRP instance MUST be of the same family. VRRP low-level framework create socket pool based on VRRP instance family. If you are using unicast_peer, it is mandatory to use addresses of same family as VRRP instance. You cant mix IPv4 and IPv6 addresses inside same unicast_peer block. If you need to make it that way, you MUST create a VRRP instance per family, eg: one with native_ipv6 for v6 unicast_peer and another for v4 unicast_peer. * vrrp: extended unicast code to support IPv6 unicast_src_ip. Add support to unicast IPv6 address for {unicast,mcast}_src_ip keyword. vrrp instance saddr is now a sockaddr_storage and src IPv6 address is set using cmsg ancillary data pktinfo. TSource IP address selection is now generic and can be IPv4 or IPv6. * vrrp: fix vrrp socket sync while leaving FAULT state. Well, this is a very, VERY old bug here. while leaving FAULT state VRRP framework refresh instance socket fd_in & fd_out and synchronize all VRRP instance bound to the same socket. The patch refresh socket, it also refresh fd hashing ! which better for later fault handling :) * vrrp: Frank Baalbergen fix log-facility handling. log-facility should be a required_argument * vrrp: Support xmit VRRP packets from base VMAC interface. Here is a merge of patch from Oliver Smith. Thanks for your job and idea in here Oliver. Comments from Olivier : This provides a new option to use in conjunction with the VMAC functionality which will result in VRRP advertisements being sent and received over the underlying interface (and therefore having the source MAC of that interface rather than the VMAC device). With this new functionality enabled, VRRP messages will not affect the switch MAC address table since the non-unique VMAC address is now used only for sending a gratuitous ARP, thereby ensuring that in conditions of VRRP message loss, a probing partner will not inadvertently take over traffic. This also resolves issues where VRRP messages are not successfully being seen on the VMAC interface as with the new option, the underlying interface is also used to listen out for VRRP messages. * getopt: Make some arguments required * vrrp: Frank Baalbergen add default case in getopt_long. when starting keepalived with an option without an argument that requires an argument keepalived should not be started. * vrrp: VMAC code cleanup and extensions. Remastered VMAC code. Interface base_ifindex is set by default to interface ifindex during netlink probe. VMAC interface base_ifindex is now set during VMAC allocation uppon success interface creation. Detect if virtual_router_id is declared after use_mvac keyword is invoked. Add some more log while setting up and removing VMAC interface. * vrrp: IPv4 & IPv6 multicast group tweaking. Meno Abels extended vrrp framework to support customized multicast addresses. The address could be set for ipv4 and ipv6 in the global_defs config section using the keywords vrrp_mcast_group4 and vrrp_mcast_group6. There are some stupid switches which does a special processing to 224.0.0.0/8 multicast packets which causes packets drop from queue overflows in environments which creates 100 and more multicast control plane packets a second. 2013-11-10 Alexandre Cassen * keepalived-1.2.9 released. * Alexey Andriyanov fixed inaccuracy in VS_ISEQ macro. * Alexey Andriyanov fixed hysteresis which could be >= quorum now. * Alexey Andriyanov extended checker framework so that status_code and digest can be set together. * Alexey Andriyanov extended/fixed checker framework for better SIGHUP support. * Jonas Johansson fixed VRRP sync group by sending prio 0 when entering FAULT state. This fix will send prio 0 (VRRP_PRIO_STOP) when the VRRP router transists from MASTER to FAULT state. This will make a sync group leave the MASTER state more quickly by notifying the backup router(s) instead of having them to wait for time out. * Jonas Johansson extended VRRP VMAC interface flags (up/down status) to follow base interface. When using a VMAC interface, this fix will reflect the base interface flags, i.e. up/down status, to the VMAC interface. This is useful when using sync groups (in combination with VMAC) and a link for one of the members in the MASTER sync group goes down. Before this fix, this member will not detect the link fault, due to that the VMAC interface always is UP regardless of the actual status of the base interface, and the sync group will continue to be MASTER as if nothing has happend. This fix will however reflect the status of the base interface onto the VMAC interface, so if the link goes down the member will transit to FAULT state, which will make the sync group transit to BACKUP state. * Jonas Johansson fixed VRRP wrong interface flags corner case. If a link event arrives between the initial scanning for interfaces and configuration file parsing, the VRRP instance will enter an unrecoverable state. This fix will update the interface flags even when the interface exists, not only for the inital scan. Note that when all is up and running the link events will be properly handled by netlink, so this fix only fixes the special case when a link changes state during initalization/configuration. * Jonas Johansson fixed VRRP to honor preempt_delay setting on startup. If the preempt_delay is set we cannot yet transition to master state. We must await the timeout of our preempt_delay. The preemption delay is used when starting up, or rebooting, a node which needs time to sort out its routing table (e.g., BGP or OSPF) before it can assume the master role. * Jonas Johansson extended VRRP code for faster sync group transition. * Jonas Johansson replaced popt with getopt. In a embedded environment you might not want to have to add yet another library dependency. This commit refactors parse_cmdline() to use getopt_long() instead och popt. * EyckWigo proposed to increase defaut socket buf size to handle env with lot of IP addresses, Default is now set to 64K on netlink socket. * Guðmundur Bjarni Ólafsson fixed VRRP unicast code to allow packet to be routed ! * Guðmundur Bjarni Ólafsson fixed VRRP checksum before computation. When running in unicast mode with multiple peers, the checksum was being calculated into itself for consequent peers, causing incorrect checksums. * Extended VRRP framework tweaking IPv6 VIP install by disabling DAD algo and setting deprecated. Lot of discussions have been made around those 2 topics. First idea and initial patch where provided by Leo Baltus. This patch fix the use case where VRRP VIPv6 are used in conjonction of IPVS healthchecking. If deprecated flag is not set (which is the default linux behaviour), then VRRP VIP can be used as source address of healthcheking packet. Since this VIP address is also present, in most use-cases, on realserver directly so return packets never reach the healthchecker and hence no realserver was injected in IPVS table. At the same time, I decided to merge Tore Anderson suggestion of disabling Duplicate Address Detection algorithm. Tore's arguments are nice ! Thanks Tore : Using the nodad flag has the following benefits: 1) The address becomes immediately usable after they're configured. 2) In the case of a temporary layer-2 / split-brain problem we can avoid that the active VIP transitions into the dadfailed phase and stays there forever - leaving us without service. HA/VRRP setups have their own "DAD"-like functionality, so it's not really needed from the IPv6 stack. Acknowledgements to Mark Schouten and Frank Baalbergen for pushing me by testing this features ! 2013-09-05 Alexandre Cassen * keepalived-1.2.8 released. * Vincent Bernat fixed issue while pinging master agent. The agent needs to be initialized to be able to change the AgentX ping interval. * Revisited the whole code to use posix declaration style. * fixed some typos * Created CLI core framework. * Ryan O'Hara added option to prevent respawn of child process. This patch adds a command-line option (--dont-respawn, -R) that will prevent the child processes from respawning. When this option is specified, if either the checker or vrrp child processes exit the parent process will raise the SIGTERM signal and exit. * Ryan O'Hara removed duplicate command-line option code. patch removes unnecessary code to process command-line options. All options can be processed with a single while loop that calls poptGetNextOpt. This patch also adds code to check for errors while processing options. Note that errors encountered while processing command-line options are fatal. * Ryan O'Hara add support to usage generation by popt. This patch uses the popt library to describe the command-line options and print usage to stderr. This provides a more clear, concise usage statement. * Ryan O'Hara and I updated keepalived man page. * Aleksei Ilin add flexible HTTP checker behaviour for HTTP GET request's port settings. VirtualServer's port being specified in HTTP GET request only if `VirtualHost` option is not defined, otherwise used `VirtualHost` option itself. * Ryan O'Hara fixed pointer arithmetic for VRRP packet. When using IPSEC AH authentication, the pointer arithmetic used to get the location of the VRRP packet is incorrect. The address of the IPSEC header must be cast as (char *) in order to get correct address of the VRRP packet. Without this patch, vrrp_in_chk() will fail to verify incoming VRRP packets when IPSEC AH is enabled. * Ryan O'Hara fixed issue while loading SSL certificate. This patch fixes a problem where keepalived will attempt to load an SSL keyfile as a certificate, resulting in failure to initialize SSL context. * Ryan O'Hara refreshed GPLv2 license with last FSF file. * junpei-yoshino fixed configure.in. Library crypt is needed. * Boon Ang fixed comparison of primary IP addresses. If a router in the master state receives an advertisement with priority equal to the local priority, it must also compare the primary IP addresses (RFC 3768, section 6.4.3). The code to handle this was comparing two IP addresses with different byte-ordering, resulting in multiple routers in the master state. This patches resolves the problem by coverting the local primary IP address to network byte order for the comparison. * Henrique Mecking fixed memory leak in libipvs * Robert James Hernandez fixed RETVAL by setting RETVAL for status instead keeping RETVAL set to default of 0 * Robert James Hernandez fixed RETVAL by setting RETVAL for catch all and so that it exits like all other matches in the case * Jan Pokorný fixed genhash to ensure CLRF{2} HTML body separator won't slip. * Jan Pokorný extended genhash. Generalize the hash algoi parts, add SHA1. This patch adds support for hash algo suite extension with SHA1 being a first one to be available together with a default MD5. The remaining change on the health-checker subsystem side is to make analogous modifications and to teach it to recognize the intended hash algorithm based on the length of the digest (provided that extra care is taken that no two algorithms will ever alias in this regard). Also the test script for genhash was extended to conditionally use SHA1. * Jan Pokorný cleaned up genhash code. Access to the hash-specific context was simplified as I've now checked some C guarantees regarding union/it's members initial address vs. aligning so now extra inlined accessor function is needed. This simplified the code a bit. Also now the hash-specific object is directly pointed to by SOCK object instead of carrying just the index to the table of hashes and doing the respective access via a global again and again. Next, I've concentrated some hash-related declarations to the new hash.h file. This was mostly motivated by a need to break the circular include dependency that have arisen. As a consequence, part of the recent clutter I brought in was removed again. Most of FEAT_SHA1 conditional compilation is here. Previously separated table in main carrying the hash IDs to be printed in the help screen was merged into the table carrying all the other necessary information about the particular hashes. * vrrp: Remi Gacogne fixed invalid use of sizeof. * Pasi Kärkkäinen Add To header for SMTP alerts. * vrrp: Robert Sander add IPv6 support for virtual_routes and static_routes. * Erik de Groot add support to LVS One-Packet Scheduling (known as OPS). Typically RADIUS traffic comes from a limited amount of clients and thus you have a very limited range of IP tuples in action which will never expire. Issue with Keepalived without this patch is that, although it correctly re-assigns traffic when a real server dies, it will never re-assign traffic back to the real server when it is restored. This is because LVS creates virtual connections, for each IP tuple, that will never time out as the clients keep sending traffic to the server. With this patch is is possible to enable OPS for UDP virtual servers which means LVS does not create virtual connections and takes a new loadbalancing decision for each UDP packet. The result is that a restored server now gets RADIUS traffic as soon as LVS has taken it it back into the server pool. * Willy Tarreau and Ryan O'Hara add the ability to use VRRP over unicast. Unicast IP addresses may be specified for each VRRP instance with the 'unicast_peer' configuration keyword. When a VRRP instance has one or more unicast IP address defined, VRRP advertisements will be sent to each of those addresses. Unicast IP addresses may be either IPv4 or IPv6. If you are planing to use this option, ensure every ip addresses present in unicast_peer configuration block do not belong to the same router/box. Otherwise it will generate duplicate packet at reception point. 2012-08-29 Alexandre Cassen * keepalived-1.2.7 released. * vrrp: fix issue in while using vrrp_script. Previous patch introduced by Ryan O'Hara about removing shadow declaration was kind of too much hunting. Removing element e in this block simply create inconsitency in upper list walk. So resurected element declaration with e2. * snmp: Mikhail Gaydamaka extended MIB and both vrrp and check frameworkds to support routerId to var bind. * snmp: Mikhail Gaydamaka fixed oid for vrrpSyncGroupStateChange var bind. * some cosmetics again and again. 2012-08-20 Alexandre Cassen * keepalived-1.2.6 released. * Rename global config data variable 'global_data'. From Ryan O'Hara : This patch renames the global configuration data variable from 'data' to 'global_data'. Three reasons for renaming this varibale: - Fixes shadow declaration of 'data' in several locations. - Is more consistent with other global data variables (ie. vrrp_data, check_data). - Functions like free_global_data and dump_global_data were ignoring conf_data_t argument and using global variable instead. * Ryan O'Hara: Fix shadow declaration of 'vrrp_data' variable. * Ryan O'Hara: Fix shadow declaration of 'check_data' variable. * Ryan O'Hara: Remove shadow declaration of 'element e' in vrrp_init_state. * check: Avoid the use of kernel defines in libipvs userland prototypes. * vrrp: Correctly handle macvlan interface when config file is re-loaded. From Bob Gilligan : Testing with the 1.2.0 branch, bring keepalived up with a vrrp_instance that is configured with use_vmac. Then delete that vrrp_instance from the config file. Then tell keepalived to re-read its config file with SIGHUP. The vrrp_instance will be stopped, but the macvlan interface will remain. The obvious fix would be to add code to call netlink_link_del_vmac() in clear_diff_vrrp(). There's one problem with that: the code needs the ifindex of the macvlan interface to delete it, but that resides in the interface structure that was freed earlier in the reload process. My fix is to add a field to the vrrp_rt struct to remember the macvlan ifindex. This patch addresses this problem plus two others that can occur in reloading the config file: 1) If the vrrp_instance configuration is kept, but the use_vmac entry is removed, the macvlan interface will not be deleted; 2) If a vrrp_instance with use_vmac is left unchanged, the code will attempt to re-create the macvlan interface, but this will fail and the program will end up not using the macvlan interface. * vrrp: VRRP should notify other routers before it does any action that effects traffic flow. From John Southworth: Move the shutdown_vrrp_instances code to before the deletion of sock_pool. Move sending priority 0 adverts to before address removal occurs * vrrp: From John Southworth: Stop timers before shutting down vrrp instances. This is to avoid a possible condition where a priority 0 advertisement is sent and before the master thread is killed another advertisement can be generated and sent. * vrrp: Change when socket fd's are freed. From John Southworth: Priority 0 advertisements were not being sent as desired on config reload. This was causing long delays on manually failed over instances. The socket pool was being freed too early, as a result the file descriptor for the socket was no longer valid at the time the priority 0 advertisment was attempted. * vrrp: Added a separate timeout parameter for vrrp_script checks From Jonathan Harden: I've added a timeout parameter to the vrrp check scripts which allow you to have the check timeout different to the interval. When no timeout has been specified the interval is used (which mimics the current behaviour). To explain the reasoning: We wanted to have check scripts time out faster than our check interval. Doing the check we need to perform is a little load intensive and so we don't want to perform it every few seconds. With this patch we set an interval of 60 seconds but a timeout of 5 seconds (if the check takes more than a few seconds then the service is not working correctly). * Extended vector lib for futur work * some cosmetics. 2012-08-13 Alexandre Cassen * keepalived-1.2.5 released. * Merge SNMP support from Vincent Bernat. * SNMP is not compiled nor activated by default. * Updated autoconf script * Created Keepalived MIB * Integration of NetSNMP into main scheduling loop * vrrp: Most internal data can be queried with SNMP. * check: Most internal values can be queried using SNMP. The main exception is the ability to query checkers which is not present. * check: SNMP support for IPVS stats. IPVS stats are exported with SNMP. A cache is used to avoid to query the kernel too much. * Created core framework for SNMP trap * vrrp: SNMP traps are sent when instance state changes and when sync group state changes * check: SNMP traprs are sent when real server state changes and when virtual server quorum state changes * vrrp: add support to write/update operations from SNMP. Write/update support is available for changing the base priority and for changing instance preemption. * check: add support to write/update operations from SNMP. Write support is available for changing the weight of a real server. * workaround for AgentX ping blocking Keepalived. When establishing AgentX session with the master agent, we setup low timeout and retries values. If the master agent is blocked, we will wait for less than 1 second for them and therefore, there will be no disruption for VRRP. * Copyright update * some cosmetics. 2012-07-27 Alexandre Cassen * keepalived-1.2.4 released. * Please look at git repo for credits. * remove CR from manpage * check: fix pid display in syslog messages * vrrp: better documentation of the limitation on password length * cosmetics to be pleasant with GCC4 * Update autoconf script to properly detect VRRP VMAC support * security: Fix exploitable issue in sighandler ! * Add datarootdir to Makefile.in files. * Fix logging to console. * Remove newlines from log_message calls. 2012-07-13 Alexandre Cassen * keepalived-1.2.3 released. * Please look at git repo for credits. * VRRP : allow group to use priority with 'global_tracking' group keyword * VRRP : Adjust TOS values. The TOS value used by other vendors is ip precedence 6, so change that. Use socket priority option to force packets into band 0 of pfifo_fast. * VRRP : Fix sync-group thrashing.The sync group implementation was not very robust. If one synced instance lost communication without going to fault state then all synced intances would transition to master. Following this all instances would transition back to backup because they heard higher priority advertisements. This thrashing would continue indefinitely. To fix this the sync-group code was made to prefer backup state. That is, the sync-groups don't sync to master state unless every instance wants to be master. * VRRP : Fix dst lladdr in IPv6 Unsollicited NA. * VRRP : fix pid display in syslog messages. * Fix configure script to correctly identify kernel version. * check : handle unspecified sockaddr_storage when comparing * VRRP : ensure VRRP script interval and GARP delay is not 0. * check: ensure non 0 default values for timeouts. * VRRP : Fix priority not changing on reload. * check : Fix IPv4 address comparison routine. * Don't use bind() with AF_UNSPEC. * check : enable the use of fwmark with IPv6 virtual servers. * Fix modprobe arguments. * Fix double ntohs() in SMTP checker. * Pretty-print IP:port as [%s]:%d. * check : keep retry in case of early TCP failures in checks. * when specifying an IPv6 range, range is hexadecimal value. * Only define kernel types for ip_vs.h header to avoid problems when loading other headers. * When respawning VRRP or check process, use LOG_ALERT. * Do not set reload flag in the main process. * Set correct rights on PID file. * fix 'gratuitous' typos. * ipvs: don't include linux/types.h or asm/types.h. * configure: check for nl_socket_modify_cb for libnl. * configure: don't check for IPVS support with kernel 2.6.x. * VRRP : On shutdown, release sockets later to be able to send shutdown packet. * fix documentation on linkbeat_use_polling keyword. * Fix a typo for healthchecker. * fix syslog message if bogous vrrp packet (wrong auth type) received. * manpage update. 2011-01-09 Alexandre Cassen * keepalived-1.2.2 released. * IPv6 : extended autoconf script to support libnl detection. IPv6 IPVS kernel subsystem is reachable through generic netlink configuration interface. * IPv6 : Enhanced libipvs-2.6 to support generic netlink configuration interface. If generic netlink is available with kernel then it will be the prefered path to configure IPVS. * IPv6 : Enhanced the whole checker API to use sockaddr_storage. * IPv6 : Enhanced the whole core framework to use sockaddr_storage. * IPv6 : Enhanced all checkers to use sockaddr_storage. * fixed a long time pending issue in all checkers. If first connection attempt to remote peer was failing no more check was performed to service... Up on error connecting remote peer simply register a new timer for next check. This is specially needed in IPv6 context where a unreachable host can be reached at delayed time. * code clean-up: revisited the code to use more POSIX compliant declaration. thread typedef to use thread_t instead. revisisted checker framework to use POSIX typdef declaration. 2010-12-08 Alexandre Cassen * keepalived-1.2.1 released. * Vincent Bernat luffy.cx>: VRRP: Fix incorrect computation for packet size * Vincent Bernat luffy.cx>: VRRP: handle passwords up to 8 characters * Vincent Bernat luffy.cx>: When updating weight, check quorum state. MISC check can update the weight of a real server. This can lead to a change in quorum state. We factor out quorum handling from perform_svr_state() into a new function update_quorum_state() that will check if the quorum state changed and if yes, update sorry server status, exec quorum commands and add back or remove alive real servers (with existing function perform_quorum_state()). This patch is mostly cut'n'paste and adding a call to update_quorum_state() in update_svr_wgt(). We also make perform_svr_state() and update_quorum_state() almost symmetric. * Vincent Bernat luffy.cx>: Fix an infinite loop in master transition with sync groups. This patch is from Arjan Filius. See: http://marc.info/?l=keepalived-devel&m=128212278218825&w=2 When transitioning to master state, keepalived might try to force transition to master state of other VRRP instances into the same group before their transition is complete. This leads to an infinite loop with huge VRRP trafic. * Vincent Bernat luffy.cx>: VRRP : Use VRRP_PRIO_DFL instead of 100 for default priority. * Vincent Bernat luffy.cx>: Use netpacket/packet.h instead of linux/if_packet.h to get sockaddr_ll. linux/if_packet.h pulls linux/types.h that should not be used by a userland program since types defined here can conflict with stdint.h. We use netpacket/packet.h which is a GNU LibC header. * Vincent Bernat luffy.cx>: Keep current weight on reload when initial weight is not altered. Weight can be changed by MISC_CHECK when using dynamic option. In case of reload, the change is lost until the script runs again. We record the initial weight in a separate variable and use it to check if a real server has changed instead of using the actual weight. * Vincent Bernat luffy.cx>: VRRP : disabled scripts and initially good scripts should be considered as OK. When a script is not weighted, its failure will lead to a failure of the associated VRRP instance. However, disabled script and scripts that are initially good (after a reload) should be considered as successful and not make the instance fail. Moreover, a disabled script should not be used when computing script weights. * Vincent Bernat luffy.cx>: VRRP : more informative message when disabling a script due to use of weights. When using a weight for a tracked script, the script is disabled. However, the warning message said that the weight was ignored. We change the message to tell that the script is ignored. Moreover, we don't change its weight since it can be used in another instance, not in a SYNC group. * Vincent Bernat luffy.cx>: check : include missing virtual server group name in a log message * Vincent Bernat luffy.cx>: configure: add a check for ETHERTYPE_IPV6. ETHERTYPE_IPV6 defined in net/ethernet.h is pretty recent. If absent, we hard-code the value into CFLAGS. This patch requires regeneration of configure. * Vincent Bernat luffy.cx>: check : update server weight in IPVS only if server is alive and in the pool. With inhibit_on_failure, a server can be in the pool and not alive. We don't want to set the weight of an inhibited server or a server in a virtual server whose qorum is not met yet. * Vincent Bernat luffy.cx>: check: really add back inhibited server when quorum is gained A previous change contained an erroneous check to add back alive servers when quorum state was gained. This check was incompatible with inhibit_on_failure. When servers were added back in the pool, the weight was not updated accordingly. * Vincent Bernat luffy.cx>: check : update server weight despite quorum when no sorry server. In absence of a sorry server, the logic is to not use quorum except to run commands when quorum is gained or lost. This means that if a MISC check modifies the weight of a server and there is no sorry server, we do not consider quorum. 2010-05-31 Alexandre Cassen * Branch 1.2.0 created. This branch will host all new developments on Keepalived. New code will be added in here only. * VRRP : Add support to IPv6 protocol. The global framework has been extended to support this branch new family ! * VRRP : Implement IPv6 Neighbour Discovery protocol (NDISC). In IPv6 gratuitous ARP doesnt exist since ARP is IPv4 only. NDISC can provide the same feature by sending so called Unsolicited Neighbour Advertisement. A node can send such a protocol datagram in order to (unreliable) propagate new information quickly (rfc4861.4.4). NDISC build an ICMPv6 message with taget link-layer address option, this option is set icmp6_override flag to indicate that advertisement should override an existing cache entry and update the cached link-layer. * VRRP : Extend ip address framework to be IPv4 and IPv6 independant. An ip address, as defined in framework, is now {IPv4,broadcast} or {IPv6}. Use struct ifaddrmsg to store and prepare netlink related operation. This clean- -up the code. * VRRP : Extend parser to support IPv6 declarations. IPv6 and IPv4 addresses can be configured inside the same configuration block (eg: virtual_ipaddress or virtual_ipaddress_excluded). An instance can run IPv4 and IPv6 addresses at a time, this can be useful in dual-stack env (since this will become certainly the most common use case in the next years). * VRRP : Extend netlink framwork to support IPv6 addresses interactions (reflection/addition/deletion). * VRRP : Extend finite state machine support IPv4 & IPv6 at a time. * VRRP : Extend protocol helpers to support IPv6 multicast related. AF_INET6 SOCK_RAW tweaking it done through socket API instead of PF_PACKET header building... This makes code cleaner. * VRRP : Set default VRRP instance protocol to be IPv4. you can use configuration keyword "native_ipv6" inside vrrp_instance configuration block to specify that you want to use IPv6 for VRRP multicasting protocol instead. * VRRP : Extend socket option related helpers to support IPv6 specifics. * VRRP : Extend protocol scheduler and dispatcher to support IPv6. * VRRP : Extend socket pool to keep track of socket family. * VRRP : Cleanup protocol offset pointer by removing duplication code... * VRRP : some code clean-up... 2010-05-06 Alexandre Cassen * keepalived-1.1.20 released. * Vincent Bernat luffy.cx> extended ip/route framework to be able to add route or ip address if they already exist. * Vincent Bernat luffy.cx> fixed broadcast address display. * Vincent Bernat luffy.cx> extended genhash to display an error when giving an incorrect IP address. * Vincent Bernat luffy.cx>: When parsing "blackhole" route, also parse IP mask. * Vincent Bernat luffy.cx>: On reload, destroy signal pipes before recreating them. * Vincent Bernat luffy.cx>: Fix SMTP checker adding himself repeatedly in the list of failed checkers. * Vincent Bernat luffy.cx>: Handle non-existant default interface in VIP definition. * Vincent Bernat luffy.cx>: Remove alive real servers when quorum is lost. * Vincent Bernat luffy.cx>: Fix a segfault when a virtual_server is empty. * Vincent Bernat luffy.cx>: Add real servers to new member of a virtual server group on reload. * Vincent Bernat luffy.cx>: Keep previous effective VRRP priority on reload. * Vincent Bernat luffy.cx>: Fix VRRP script not running any more after reload. * Vincent Bernat luffy.cx>: On reload, keep status for all VRRP scripts. * Removed IPVS Kernel 2.2 support 2009-10-01 Alexandre Cassen * keepalived-1.1.19 released. * Cosmetics changes. * Vincent Bernat luffy.cx> fix a segfault when there is no real server for a virtual server. * Vincent Bernat luffy.cx>, Willy Tarreau and I finally fixed SIGCHLD handling upon reload. * Vincent Bernat luffy.cx> fix VS_ISEQ macro. * VRRP : Kimitoshi Takahashi clustcom.com> fixed nopreempt from FAULT state. The owner of higher priority in FAULT state shouldn't preempt current MASTER when it's recovering, if the nopreempt option is set. 2009-09-24 Alexandre Cassen * keepalived-1.1.18 released. * Fixed compilation warnings * Updated autoconf kernel version detection. Created a new configuration option to force kernel versioni selection. This option can be useful for crosscompilation: --with-kernel-version={2.2|2.4|2.6} * Updated media link failure detection strategy. Kernel linkwatch has been around for long time so set it as default strategy. Alternatively you can choose to use MII BSMR polling strategy by adding new keyword 'linkbeat_use_polling' in your configuration file. * Vincent Bernat luffy.cx> fixed ip_vs.h includes. * Removed vrrp_running and check_running test since it is already performed by keepalived_running. * Properly handle father pidfile handling. * fixed reload handler to properly print out PID. * Willy and I fixed a signal handling issue while reloading daemon. A dereferencing master thread issue leading to a segfault, so that reload was seen as a restart because it was respawned by keepalived father process. * Willy fixed a missing UNSET_RELOAD declaration leading to a potential infinite loop while performing reload. * Vincent Bernat luffy.cx> fixed initial value of quorum state on startup and reload. Fixed sorry server removal to consider quorum state. * VRRP : Add missing notify calls while entering FAULT state. * VRRP : Willy added support to delayed script check launch (up and down). It defines "rise" and "fall" keywords. "fall" defines the required number of failures to switch in KO mode, "rise" defines the number of sucesses to switch in OK mode. * VRRP : Fixed an IP_DROP_MEMBERSHIP issue while performing reload. vrrp socket pool is released at first. 2009-03-05 Alexandre Cassen * keepalived-1.1.17 released. * Fixed low-level scheduler timer computation to take care to monothonic computation. Select returns if timer is null! * VRRP : Fixed vrrp script initialization to use event thread instead of timer thread so that script no longer need to wait until first polling timer fired. * VRRP : Willy and I fixed MII media link failure detection to test SIOCGMIIREG call before fetching BMSR. * VRRP : Resurected VRRP_STATE_GOTO_FAULT. This state is really needed to speed-up convergence and prevent against any issue while using vrrp_sync_group. 2009-02-15 Alexandre Cassen * keepalived-1.1.16 released. * Code clean-up. * Stefan Rompf, extended scheduler to synchronize signal handling by sending the signal number through a self pipe, making signals select()able. Child reaping has been moved to a simple signal synchronous signal handler. Signal shutdown handling has been centralized. * Denis Ovsienko, extended healthchecker framework to support alpha/omega design. It provides virtual service control in a more fine-graned maner. You may have a look to the SYNOPSIS file to have full picture on configation. It addresses the following issues : - A virtual service is considered up even with an empty RS pool. - There is no reliable mean to avoid service regression, when the server pool becomes too small. - There is no mean to escalate any of the above fault/recovery events. - Real servers are assumed alive initially. This leads to unnecessary state flap on keepalived start. - notify_down isn't executed for working real servers on keepalived shutdown. - There is no reliable mean to handle keepalived stop to move the virtual service over another load balancer. * Stephan Mayr, fixed default value for checker loop... a missing TIMER_HZ. * Merge keepalived.init.suse. * Robin Garner, added support to --log-console facility. * Tobias Klausmann, fixed an openfile leak while performing reload. * Leo Baltus, extended pidfile handling to allow keepalived to start using configurated pidfile. * VRRP : Siim Poder, fixed IPSEC AH auth to skip IPv4 id field of zero. If zeroed kernel will fill it and lead to an unwanted protocol re-election. * VRRP : Siim Poder, fixed reloading issue. New ip addresses are added (from configuration). State is kept instead of starting from whatever is in configuration file. If prios are changed in such a way, state change can occur after reload. * VRRP : Vincent Bernat, extended virtual_route to support virtual "black hole" route as well as multihop route. * VRRP : Stig Thormodsrud, fixed a crash while using virtual_router_id set to 255. * VRRP: Jon DeVree, fixed arp handling to to initialize the target hardware address, using 0xff as found in arping. Let scripts work without dealing with weight, if the script fails, VRRP fails. * VRRP : Pierre-Yves Ritschard, removed the GOTO_FAULT state from FSM. * VRRP : Willy Tarreau, fixed link detection handling to support right ioctl values for recent kernel ! It can lead to issue while running instance on a bonding interface. * VRRP : Willy Tarreau, extended scheduler to catch time drift. It implements an internal monotonic clock. It maintains an offset between sysclock and monotonic clock, if computed time if anterior to monotonic time then just update offset. If time computed if fare away into the future then limit delay and recompute offset. * VRRP : Willy Tarreau, fixed autoconf issues. 2007-09-15 Alexandre Cassen * keepalived-1.1.15 released. * Matthias Saou, fixed genhash Makefile for man page installation. * Casey Zacek, provided a patch to check_http to remove buffer minimization while processing stream. It appears some webserver cause healthchecker crash. * Chris Marchesi, provided a patch for better handling of SSL handshake errors. * Shinji Tanaka, fixed parser "include" directive to support declaration inside configuration directives, like including file inside vrrp_instance declaration. * Andreas Kotes, fixed HTTP healthchecker while handling MD5SUM result. It appears checker never removed realserver on MD5SUM mismatch !!! whats that crap. * VRRP : Willy Tarreau, fixed a missing notifications upon transition from fault to backup. * VRRP : Add support to route metric in virtual_routes definition. 2007-09-13 Alexandre Cassen * keepalived-1.1.14 released. * Shinji Tanaka, extended parsing framework to support "include" directives. For more informations and documentation please refer to Shinji website : http://misccs.dyndns.org/index.php?keepalived%20include%20patch * Tobias Klausmann, add error loggin while parsing configuration file. * Merged patches from rpmforge.net on Makefile and redhat specfile. * Create a goodies directory to store nice scripts received from users. Add Steve Milton (milton AT isomedia.com) arpreset script to delete a single ARP entry from a CISCO router. * VRRP : David Woodhouse, fixed vrrp_arp includes. * VRRP : Pierre-Yves Ritschard, fixed negative weights in script. * VRRP : Michael Smith, extended virtual_ipaddress setting to support Old-style Linux interface aliases like eth0:1. * VRRP : Ward Wouts, add support to vrrp_script logging. 2006-10-11 Alexandre Cassen * keepalived-1.1.13 released. * VRRP : Added a new notify script to be launch during vrrp instances shutdown. This new notify hook is configured using notify_stop keyword inside vrrp_instance block. * VRRP : Willy Tarreau fixed an errno issue in thread_fetch(), errno is lost during set_time_now(). This patch saves it across the call to set_time_now() in order to get the valid error. * VRRP : Willy Tarreau extended timer framework to save errno in timer_now() and set_time_now() just in case other functions do not expect these functions to modify it. This is a safer approach than the initial patch to thread_fetch(), while still compatible. * VRRP : Willy Tarreau fixed an FSM silent issue. By default, the VRRP daemon stops sending during new MASTER elections. This causes 3 to 4 seconds of silence depending on the local priority, and sometimes causes flapping when the differences in priorities are very low, due to the kernel timer's resolution : sometimes, the old master receives a first advertisement, enters backup, waits 3 seconds, sees nothing and finally becomes master again, which forces a new reelection on the other one. * VRRP : Willy Tarreau extended VRRP framework to support floating priority. Replace the priority in each vrrp_instance with a base priority and an effective priority, to prepare the support for floating priorities. The configuration sets the base_priority, and all comparisons use the new effective_priority value. This one is computed in the vrrp_update_priority() thread by adding an offset to base_priority, based on the result of various checks. * VRRP : Willy Tarreau extended notify script to add the priority in "$4" when calling a notify script. This is important in labs and datacenters when systems can display the priority on a front LCD, because it allows workers to carefully operate without causing unexpected reelections. * VRRP : Willy Tarreau extended interface tracking framework to let interface tracking change the priority by adding a "weight" parameter. If the weight is positive, it will be added to the priority when the interface is UP. If the weight is negative, it will be subtracted from the priority when the interface is down. If the weight is zero (default), a down interface will switch the instance to the FAULT state. * VRRP : Willy Tarreau added a new "vrrp_script" section to monitor local processes or do any type of local processing to decide whether the machine is in good enough health to be elected as master. A same script will be run once for all instances which monitor it. If no instance use it, it will not be run, so that it's safe to declare a lot of useful scripts. A weight is associated to the script result. If the weight is positive, it will be added to the priority when the result is OK (exit 0). If the weight is negative, it will be subtracted from the priority when the result is KO (exit != 0). If the weight is zero, the script will not be monitored. The default value is 2. * VRRP : Willy Tarreau extended vrrp scheduler so that when a VRRP is part of a SYNC group, it must not use floating priorities, otherwise this may lead to infinite re-election after every advertisement because some VRRPs will announce higher prios than the peer, while others will announce lower prios. The solution is to set all weights to 0 to enable standard interface tracking, and to disable the update prio thread if VRRP SYNC is enabled on a VRRP. * VRRP : Willy Tarreau added some documentation and examples for the brand new VRRP tracking mechanisms. * VRRP : Ranko Zivojnovic, fixed vrrp scheduler to execute notify* scripts in transition from the failed state to the backup state. * Nick Couchman, , added support for real server upper and lower thresholds. This allows you to set a minimum and maximum number of connections to each real server using the "uthreshold" (maximum) and "lthreshold" (minimum) options in the real_server section of the configuration file. * Chris Caputo, extended autoconf script to support recent move of UTS_RELEASE from linux/version.h to linux/utsrelease.h. * Chris Caputo, extended ipvswrapper 2.4 code to support misc_dynamic weight. 2006-03-09 Alexandre Cassen * keepalived-1.1.12 released. * VRRP : Christophe Varoqui, extended VRRP framework to use virtual_router_id as syncid in LVS mcast datagram while using LVS syncd in VRRP instance. * Kevin Lindsay, and Christophe Varoqui, fixed SSL checker to properly use openssl when dealing with asynchronous stream handling. Kevin fixed asynchronous handling during connection stage while Christophe fixed stream handling after connection stage. * Kjetil Torgrim Homme, extended keepalived spec file to cleanly compile on RedHat enterprise 3 and 4. * Heinz Knutzen, fixed SMTP checker to overwrite default_host while parsing configuration file. A SMTP_CHECK without a "host" section should use the ip of the current real server as default. 2005-03-01 Alexandre Cassen * keepalived-1.1.11 released. * Asier Llano Palacios, extended autoconf script to support cross-compilation. * Kevin Lindsay, and I fixed a missing bitwise negation while removing signal from global signal mask. Set this operation before handler is called. This assume that bitwise negation is an atomic code generated from compiler. Since gcc 3.3 this is true. * VRRP : extended ipaddress and iproutes code to return if vip or vroutes is referencing an unknown interface. 2005-02-15 Alexandre Cassen * keepalived-1.1.10 released. * VRRP : While restoring interface, release iproutes before ipaddresses. Routing daemons needs that order for netlink reflection channel. * VRRP : Bin Guo, fixed a memory leak while calling script_open. * Kevin Lindsay, fixed some buffer overruns, NULL pointer and dangling pointer references. * Kevin Lindsay, redisigned signal handling. When a signal occurs, a global signal_mask is modified. In the main loop there is a checked to see if the signal_mask has any pending signals. The appropriate signal handler is then run at this time. This is to prevent races when modifying linked lists. * Kevin Lindsay, fixed shadowed declarations. * Christophe Varoqui, and I Extended libipvs-2.6 to support syncd zombies handling. Since ip_vs_sync.c kernel code no longer handle waitpid() we fork a child before any ipvs syncd operation in order to workaround zombies generation. * John Ferlito, and I Fixed a scheduling race condition while working with low timers. * Updated check_http and check_ssl to use non-blocking socket. * Fixed some race conditions while reloading configuration. Prevent against list gardening if list is empty ! * Fixed recursive configuration parsing function to be clean with stack. Only one recursion level. * Some cosmetics cleanup in Makefiles. 2005-02-07 Alexandre Cassen * keepalived-1.1.9 released. * VRRP : Chris Caputo, updated keepalived manpage for nopreempt and preempt_delay. * VRRP : Fixed an issue while releasing vrrp socket pool... Just release pool one time ! * VRRP : Fixed netlink framework to properly save netlink socket flags while setting blocking flags. * VRRP : Fixed a regression introduced with previous release while hashing vrrp fd bucket into fd hash index. * Patrick Boutilier, fixed an issue in the extract_html function. Read the full html header. * Chris Caputo, and I fixed compilation issue while using --enable-debug configuration option. * Extended both VRRP and Healthchecker framework to support debugging flags. * Removed the watchdog framework. Since scheduling framework support child, we register a child thread for both process VRRP & Healthcheck. When child die or stop prematuraly this launch scheduling callback previously registered. Watchdog is now handled by signaling. (credit goes to Kevin Lindsay, for nice idea). * Some cosmetics cleanup. 2005-01-25 Alexandre Cassen * keepalived-1.1.8 released. * VRRP : Chris Caputo, added "dont_track_primary" vrrp_instance keyword which tells keepalived to ignore VRRP interface faults. Can be useful on setup where two routers are connected directly to each other on the interface used for VRRP. Without this feature the link down caused by one router crashing would also inspire the other router to lose (or not gain) MASTER state, since it was also tracking link status. * VRRP : Chris Caputo, added "nopreempt" which overrides the VRRP RFC preemption default. This replaces the "preempt" keyword which was not fully implemented. "preempt" is kept around for backward compatibility but is deprecated. * VRRP : Chris Caputo, added "preempt_delay" which allows one to specify number of seconds after startup until VRRP preemption. (range 0 to 1,000 seconds) this is useful because sometimes when a machine recovers it takes a while for it to become usable, such as when it is a router and BGP sessions need to come back up. * Chris Caputo, made it so there is a useful "Date:" in SMTP alert emails. * VRRP : Chris Caputo, . In debug output log gratuitous ARPs with actual IP addresses being ARPed. * VRRP : Chris Caputo, . If started with "--dont-release-vrrp" then try to remove addresses even if we didn't add them during the current run, when it makes sense to do so. * VRRP : Chris Caputo, added a missing free_vrrp_buffer() during VRRP stop. * VRRP : Kees Bos, fixed VRRP sanity check to perform checksum computation over incoming packet and not local router instance memory representation => Better to log 'invalid vip count' instead of 'Invalid vrrp checksum' when the number of configured vips differ in the master and backup server :) * VRRP : Release socket pool during daemon stop and reload * VRRP : Refresh socket pool during reload * VRRP : Extended netlink framework to support blocking operation. During initialization, set blocking netlink channel to wait responses from kernel while parsing result. Kernel netlink reflection are still handled using non-blocking. * Jeremy Rumpf, added SMTP checker. It take a special care of smtp server return code. * Merged genhash man page * Chris Caputo, added "misc_dynamic" to a MISC_CHECK which makes it so a script can adjust the weight of a real server. * Fixed some assertion issue in memory framework. * Use router_id instead of lvs_id in the global_def configuration block (lvs_id kept for backward compatibility). * Ronald Wahl , fixed declarations to be only in includes files. * Ronald Wahl , moved the definition of variables to C files * Ronald Wahl and I fixed scanning for header/body separator in HTTP protocol * Ronald Wahl replaced memcpy by memmove where source & destination may overlap * Extended checker API to only register checkers when checker callback is defined. * Jacob Rief, fixed openlog to take care of configured log facility. * Move in_csum to util file. * Extended libraries to support some new facilities (list and vector). * Extended scheduler I/O to use timer decalred on the stack. * Some cosmetics changes. 2004-04-05 Alexandre Cassen * keepalived-1.1.7 released. * Jacob Rief, added target tarball into root Makefile to facilitate packaging (rpm & tarball). * Jacob Rief, and I unified version handling. Now only the root file VERSION is used by configure to add VERSION_STRING via config.h.in. Added VERSION_DATE included into the VERSION_STRING that reflect the building date into the version banner. * Andres Salomon, wrote the genhash manpage. * VRRP : Added ipvs_start() and ipvs_stop() calls during vrrp child start and stop stage. * Added some assertion test in memory framework to not allocate bucket if no more place. This option is only used if compiled with debug flags. * Some cosmetics patch in Makefiles and autoconf script. 2004-02-23 Alexandre Cassen * keepalived-1.1.6 released. * VRRP : Fixed scheduling timer update. Global scheduling timer is updated before each thread registering and after scheduling I/O MUX. Since is needed to take care of scheduling jitter introduced by overhead (VRRP is using low low timer so more sensitive to overhead). Thanks to Nathan Neulinger, for his quick feedback debugging time. * VRRP : Nathan Neulinger, updated vrrp dropping strategy to not reply to incoming bogus adverts. Since this can introduce flooding loop, bogus adverts are now simply silently dropped. * VRRP : Fixed a linkbeat issue while polling NIC flags. * Updated autoconf and Makefile to support 2.6 kernel IPVS code. For code readability, created 2 differents libipvs for 2.4 and 2.6 kernel . Fixed autoconf generated warning. * Extended ipvswrapper to support shared buffer user rule. This increase performances by limiting memory allocation. OTOH, created two new ipvs helpers ipvs_start & ipvs_stop to initialize ipvs subsystem. * Andres Salomon, made some cosmetics update in Makefiles to support $(DESTDIR) and $(BIN)/$(EXEC) path split. 2004-01-25 Alexandre Cassen * keepalived-1.1.5 released. * Joseph Mack, wrote keeplived manpages in doc/man/man5/keepalived.conf.5 and doc/man/man8/keepalived.8. * VRRP : Tsuji Akira, fixed a length issue while testing password field for auth_pass method. * VRRP : Willy Tarreau, fixed a quick loop in the watchdog timer thread. * VRRP : Willy Tarreau, extended scheduler to support stable scheduling time. There is now, only one time source updated before and after scheduling event. This solve sliding timer observed on some env, also known as periodically flapping issue (sometime a VRRP election is forced). * VRRP : Willy Tarreau, updated the default media link failure detection strategy to perform a ioctl ifflags even if NIC driver are supporting MII or ETHTOOL. Some buggy drivers need this. Anyway the linkwatch patch still the best solution to support efficient and scalable media link failure detection. * Some cosmetics clean-up, removed some dead files, updated autoconf and Makefile prototypes to support dependencies libs like kerberos for RedHat/Fedora distro. To compile keepalived properly on redhat 9 box, for example, run : export CPPFLAGS="-I/usr/kerberos/include" && ./configure Renamed keywords lb_kind to lvs_method and ld_algo to lvs_sched. For compatibility reasons, old keywords are still available. 2003-12-29 Alexandre Cassen * keepalived-1.1.4 released. * Refresh autoconf script to use autoconf 2.5. * Extended the autoconf script to support linkwatch kernel detection. * To work-around the SMP forking bug, added support to two new daemon starting options : --vrrp -P Only run with VRRP subsystem. --check -C Only run with Health-checker subsystem. Those options extend daemon design to support VRRP & heathchecking subsystem selection. You can now run two Keepalived daemon one invoqued with --vrrp and the other with --check. That way we workaround the forking issue by running one daemon per subsystem. * Tiddy cleanup in the daemon code. * VRRP : Extended the link media failure detection to support asynchronous NIC MII polling. The design use now, one dedicated polling thread per NIC. This reduce scheduling jitter by this way. * VRRP : Added support to kernel linkwatch subsystem. This patch that you will find a copy on the Keepalived website for the kernel 2.4 branch, provides kernel netlink broadcast events drived by NIC link media state event. That way we move from a polling design to an event design. Link events are received throught a kernel netlink broadcast socket in the userspace land. So, NIC media link failure detection is now provided by kernel netlink reflection. You can read the paper attached with the patch for indepth explanations. * VRRP : fixed timer computation to prevent against negative value. 2003-09-29 Alexandre Cassen * keepalived-1.1.3 released. * Stephan von Krawczynski, extended ip address framework to support broadcast address selection. * Extended the scheduling framework to support plain 'long' timer. Visited the layer4 framework to support this new scheduling scheme. Reviewed the checkers and VRRP framework to support long timer. * VRRP : Removed the timer micro adjust call. Its use is obsolete with the new scheduling 'long' timer support. * Jacob Rief, and I added support log level selection for main daemon. A new command line argument has been created : --log-facility -S 0-7 Set syslog facility to LOG_LOCAL[0-7]. (default=LOG_DAEMON) * Extended the HTTP checker to support non blocking read while processing stream. NONBLOCK flags is set before read operation to catch EAGAIN error. * VRRP : Diego Rivera, and I fixed a notify issue while building notify exec string. * VRRP : Diego Rivera, and I extended FSM to support BACKUP state notifiers and smtp_alert call during VRRP initialization. * Jan Vanhercke, and I extended scheduling timer computation to support micro-sec second overlap. Extended the whole scheduling framework to support this scheduling scheme while computing thread timers. * Fixed scheduling framework to support child thread timers while computing global scheduling timer. 2003-09-07 Alexandre Cassen * keepalived-1.1.2 released. * Dominik Vogt, and I extended checker framework to support multiple checkers per realserver. Each checker own a uniq id, each realserver own a list of checkers id. Realserver is considered down if one of the checkers fails. * Dominik Vogt, extended list library to support free_list_element. * Dominik Vogt, and I extended ipwrapper to support multiple checkers test. Created a checker state updater helper function to perform realserver state according to checker state. * Dominik Vogt, extended all checkers code to support multiple checker design (to not perform server state according a single checkers test). * Tobias Klausmann, and I extended layer4 framework to support socket binding to a specific ip address before calling connect(). Extended the TCP, HTTP and SSL checker to support binding selection, creating a new checker keyword named "bindto". look at doc/keepalived.conf.SYNOPSIS for more informations. * VRRP : Extended the ethtool code to be selected only if ETHTOOL_GLINK is available. This is useful for s/390 zSeries users :) since zSerie 2.4 kernel doesn't support ethtool extension. * VRRP : Gatis Peisenieks, fixed IPSEC-AH code to exclude ip header id filed while computing AH digest. Fixed AH sequence number to be set in network byte order. * VRRP : Fixed a bug in the static_ipaddress block that caused a noisy crashing startup. * VRRP : Kjetil Torgrim Homme, and I fixed a daemon crash while reloading configuration due to a vrrp_buffer not freed. * VRRP : Review the watchdog calling location. watchdog listener is reinitialized during a daemon reload. * VRRP : Diego Rivera, extended notify framework to support simple notify script call. Created a new keyword "notify", for both vrrp_instance and vrrp_sync_group. If configured, this notify script is called after FSM state transition notify scripts. look at doc/keepalived.conf.SYNOPSIS for more informations. * Review the checker watchdog calling location like VRRP. * Fixed code selection to exclude VRRP dependencies if code is configured without VRRP framework. * Extended memory lib free function to reset memory location to NULL. * Diego Rivera, extended global parser to support default handlers for lvs_id, smtp_server, smtp_connection_timeout and email_from. default values are : o lvs_id : box local name o smtp_server : localhost o email_from : uid@box_local_name o smtp_connection_timeout : 30s 2003-07-24 Alexandre Cassen * keepalived-1.1.1 released. * VRRP : Fixed an issue while reloading configuration. Fixed a dereferencing pointer. * Fixed misc checker to perform server state according to checker result !!! 2003-07-22 Alexandre Cassen * keepalived-1.1.0 released. * The release focus is : "High Performance" * Name cleanup for the healthchecking directory. use check instead of healthcheck to be in conformance with watchdog and global software architecture. * updated the SYNOPSIS file for documenting the table arg inside virtual/static_routes declaration. You can set routes refering to a specific TABLE-ID. * Added a dummy debug var in the genhash declaration code to support compilation when compilation is done with debug flag. * Added a set flag inside the real_server declaration correctly relfect the IPVS topology when inhibit_on_failure is used. * fixed a daemon.h include depandency on signal.h * VRRP : Added support to a global shared buffer for incoming advert handling. A new buffer is no longer allocated each time processing incoming advert, instead a shared room is used. * VRRP : Added support to pre-allocated shared buffer for outgoing adverts. Each vrrp instance use a 'one time' allocated buffer instead of a 'all time' one. * VRRP : Extended the socket pool design to support shared fd for the outbound channel. Now, socket pool create a sending socket and affect the fd returned to vrrp instances. This forces instances to use a shared socket instead of creating new socket for each outgoing adverts. The error detection is based on the incoming socket, so that outgoing socket is not created as long as incoming socket can not be created. * Added support to netlink ipaddress as global keyword "static_ipaddress". look at doc/samples/keepalived.conf.static_ipaddress. IP addresses specified into this block will be added during daemon bootstrap and removed during daemon shutdown. Differential conf parsing is enabled for this block, removing/adding static_ipaddress can be done on the fly sending SIGHUP signal to daemon. * VRRP : Extended track_interface to support multiple interface tracking. For those familiar with Nokia monitored circuit, this extention provide the same functionality. look at doc/samples/keepalived.conf.track_interface. * VRRP : The VRRP instance lookup framework has been extended to use a o(1) scheduling design. Rewrote the whole instance lookup to use o(1) lookup instead of previous o(n^2). When receiving incoming adverts vrrp_scheduler performs a lookup over the VRID received to get local instance representation. Since the internal instance representation is an non-sorted linked list, then we run a lookup at o(n^2) complexity that introduce lantency and scheduling jitter side effect when runing large number of instances. To avoid this limitation a static hash table of 255 buckets were created. Since lookup is performed over VRID and since VRID is 8bit fixed, then the hashkey will be VRID. In order to extend code the hashkey is based on incoming fd too. Internally, a NIC is represented by a 2 fds : sending socket and receiving socket. Those fds are NIC specific so we are using them as a hash table lookup collision resolver. With this design we can now use the same VRID on different NICs. The collision design is a linked list so lookup is o(n^2) but due to low number of entries we can consider o(1) speed. But to reach best perf, differents VRID on all instance must be used. The design can be sumed by : VRID hash table : +---+---+---+---+---+---+.........+-----+ | 1 | 2 | 3 | 4 | 5 | 6 |.........| 255 | +---+---+---+---+---+---+.........+-----+ | | +---+ +---+ |fd3| |fd1| +---+ +---+ | +---+ |fd5| +---+ This hash table is filled during configuration parsing and VRRP instances are not duplicated but dynamically pointed to optimize memory. * VRRP : The VRRP synchronization group lookup has been extended. During bootstrap a VRRP instance index is built upon sync_group instance name. This extension speed up synchronization since while synchronizing it perfoms the instance index instead of lookup by instance_name. The previous synchornization code has been rewritten to use this 'list visiting' design for FAULT/BACKUP/MASTER states synchronization. * VRRP : Optimized the vrrp_timer_vrid_timeout(...) to speed up vrid lookup over timeouted fd using a one pass lookup. * Bradley Baetz, extended the scheduler framework to support child process handling. Adding support to new thread child facility for handling child processes, and modifying the scheduling select loop & signal handling to catch SIGCHLD, and call the appropriate process. * Bradley Baetz, fixed the misc_check healthchecker using new thread child scheduling facility. Introduced a new keyword "misc_timeout" to kill processes which take too long time (default is delay_loop). SIGKILL is send to processes if they take too long time to shutdown. * Bradley Baetz, extended daemon framework to block SIGCHLD to only receive it whn its unblocked in the scheduling loop. * Extended healthchecker delay_loop to support long delay (ie: >1000s). * VRRP : Added support to a shared kernel netlink command channel for setting ip address and routes. * Extended the genhash code to support verbose output selection. command arg '-v' will generate a very verbose output. * VRRP : Extended the logging code to select verbose log output or not. This selection is done by passing the '-D' option to command line while starting daemon. By default the output is silent. * VRRP : Extended the gratuitous ARP framework to support shared buffer and shared socket. This increase performances for instances owning a bunch of VIP. * VRRP : Extended the scheduling timer computation to support timer auto-recalibrating. While computing next instance timer, the scheduler will substract the time taken by previous advert handling. This provide software overhead adaptation. The recalibration is performed over usec timer to not pertube global scheduler. * VRRP : Fixed a gratuitous ARP issue. Extended the ipaddress framework to point directly to interface reflected by netlink channel instead of storing device index. Extended the gratuitous ARP code to use new ipaddress structure and for sending garp over device ipaddess belong to. Needed if you run an instance on one device interface and set VRRP VIP on different interface. * Extended watchdog framework to support polling delay selection via daemon command line. Created two new cmdline options : --wdog-vrrp -R Define VRRP watchdog polling delay. (default=5s) --wdog-check -H Define checkers watchdog polling delay. (default=5s) * Extended SMTP code to support bigger buffer while processing remote mta messages. * Erik Barker, extended initscript to support native redhat init functions. * Extended the autoconf scripts and Makefile(s) to support code profiling. New configure option : --enable-profile * list library has been extended to support multi-sized list & specific element deletion. Extended to return when list is empty. This reduce duplicated code to test is list is empty while processing. * VRRP : Extended VRRP scheduler to support fd hash table design. Speed up instance lookup while computing instance sands. This offer o(1) design if we consider limited number of instances per device. * VRRP : Extended vrrp new socket creation to replace refreshed instance fd into fd hash table index. * VRRP : Extended vrrp framework to support blank virtual_ipaddress block, can be usefull if someone want to use just the VRRP advert as hello monitoring channel. * Some code cleaning. 2003-05-12 Alexandre Cassen * keepalived-1.0.3 released. * This release has been sponsorized by : Tiscover AG, Please visit sponsor homepage. I would just like to thanks their IT team for interresting design discussions and testing time, especially Jacob Rief. * This release consist of a major daemon re-design to increase security and availability of Keepalived. The daemon has been splitted into 3 distinct process. The global design is based on a minimalistic parent process responsible for monitoring its forked children process. Then 2 children process, one responsible for VRRP framework and the other for healthchecking. Each children process has its own scheduling I/O multiplexer, that way VRRP scheduling jitter is optimized since VRRP scheduling must be more sensible than healthcheckers. On the other hand this splitted design minimalize for healthchecking the usage of foreign librairies and minimalize its own action down to and idle mainloop in order to avoid malfunctions caused by itself. The parent process monitoring framework has been called watchdog, the design is : each children process open an accept unix domain socket, then while daemon bootstrap, parent process connect to those unix domain socket and send periodic (5s) hello packets to children. If parent cannot send hello packet to remote connected unix domain socket it simply restart children process. This watchdog design offer 2 benefit, first of all hello packets sent from parent process to remote connected children is done throught I/O multiplexer scheduler that way it can detect deadloop in the children scheduling framework. The second benefit is brought by the uses of sysV signal to detect dead children. When running you will see in process list : PID 111 keepalived <-- parent process monitoring child activity 112 \_ keepalived <-- VRRP children 113 \_ keepalived <-- Healthchecking children * Parent : Created a global data and global keyword parser structure. * Healthcheck framework : Defined check_conf_data to handle related checker data structures. Created specific checker framework parser. * VRRP framework : Defined vrrp_conf_data to handle related vrrp data structures. Created specific vrrp framework parser. * Each child process has its own syslog facility. VRRP use LOG_LOCAL1 and Healthchecker LOG_LOCAL2. To split log you can so configure your syslog to log both facilities in a different logfile. * Modularized the configuration parser to limit code duplication. * Created modularized software watchdog. * Extended the recursive stream parser to use sublevel detection while stream processing. Used to skip end-of-block handling if still at keyword root level to prevent against end parsing if unknown block is parsed. * Extended pidfile framework to be more generic. * Extended memory framework to log specific child data. * Fixed a virtual_server_group issue while healthchecker bringing back real_servers. Modularized virtual_server_group API. * Fixed a virtual_server_group issue will reloading configuration. Remove vsgname test from the VS_ISEQ macro. strcmp(...) comparing null pointer... this must have been done in libc :) * ipwrapper : set alive flag after ipvs_cmd(...) has been performed. * VRRP : Extended the netlink framework to support SCOPE selection for both ipaddress and routes fonctionnalities. SCOPE available are site, link, host, nowhere & global. Default value is set to global. look at doc/keepalived.conf.SYNOPSIS for more informations. * Renamed doc/samples/keepalived.conf.routes to doc/samples/keepalived.conf.vrrp.routes. * Updated Makefile include dependencies. 2003-04-14 Alexandre Cassen * keepalived-1.0.2 released. * This release has been sponsorized by : edNET, Please visit sponsor homepage and thanks to them for supporting keepalived project. * Added support to virtual_server_group so that a virtual_server can be either an IP:PORT, a fwmark or group. A group is a set of virtual_server IP:PORT, IP range and fwmark. So, now a real_server can be part of multiple virtual_server without launching multiple time the same healthchecker that finaly flood real_server. This extension is useful for big ISP/ASP configuration using many virtual_server. look at doc/samples/keepalived.conf.virtual_server_group. * Extended differential configuration parser to support diff virtual_server_group entries keeping current entry state as persistent (weight, conn, ...) big work here... * Added support to IP range declaration for virtual_server_group. The IP range has the notation XXX.YYY.ZZZ.WWW-VVV. This will set IPVS virtual_server from WWW to VVV monotonaly incremented by one. look at doc/samples/keepalived.conf.virtual_server_group. * Dominik Vogt, enhanced SIGCHLD handler to reap all zombie child processes. * Created a generic allocation value block with callback handler for block parsing. This remove duplicated code in parser. * VRRP : Jan Holmberg, extended the virtual_routes and static_routes to support source route selection (netlink RTA_PREFSRC). look at doc/samples/keepalived.conf.routes. * Some cosmetics patches to reduce code duplication. 003-03-17 Alexandre Cassen * keepalived-1.0.1 released. * This release has been sponsorized by : Creative Internet Techniques, Please visit sponsor homepage, open minded people here ! * Fixed some Makefile and autoconf code dependence issues. * Move keepalived.conf.SYNOPSIS and samples into "doc" directory. * Enhanced HTTP|SSL check to support large url. Get buffer request is now 2KBytes. * Removed \n in healthchecker smtp_alert call. This cause some troubles with MTA like qmail. Thanks go to John Koyle, . * Added support to netlink route as global keyword "static_routes". look at doc/samples/keepalived.conf.routes. Routes specified into this block will be added during daemon bootstrap and removed during daemon shutdown. Differential conf parsing is enabled for this block, removing/adding static_route can be done on the fly sending SIGHUP signal to daemon. * VRRP : Added support to "virtual_routes". This is the same as virtual_address. Those routes are set when VRRP instance enter MASTER state and removed otherwise. Differential conf parsing is enabled for this block. This concept extend VRRP and bring dynamic routing as a "route takeover" concept. * VRRP : Rewrote the VRRP vip handling to use template lib list structure. VIP and E-VIP are no longer a simple array reallocated. List library is used to limite code duplication. * VRRP : Extended virtual_ipaddres and virtual_ipaddress_excluded block to support "dev" specification. So that a VIP can be set to a specific interface instead of default runing VRRP instance interface. * VRRP : Added support to "track_interface". Interesting for use with vlan interface. The concept here is to drive VRRP FSM according do both "interface" and "track_interface" state. If tracked interface is down or instance interface is down then VRRP instance transit to FAULT state. For use with vlan, add track to interface vlan belong to. Look at doc/sample/keepalived.conf.track_interface for sample. doc/keepalived.conf.SYNOPSIS for configuration details. * VRRP : Extended FSM FAULT state to keep in fault if track_interface still fault. * VRRP : Extended sync group design to test if group is unary or not. * Some code cleaning and cosmetics enhancements. 2003-01-06 Alexandre Cassen * keepalived-1.0.0 released. * After fixed all bugs users reported during 2 months, I am glad to announce the first STABLE production ready Keepalived release. * Rename keepalived.init to keepalived RedHat startup script. Fixed some issues to be RedHat release generic. Thanks go to Jeroen Simonetti & Jason Gilbert * Jason Gilbert, cleaned keepalived.spec. * Added support to "ha_suspend" for healthcheckers. This option, if set, inform Keepalived to active/suspend checkers according to netlink IP address information reflection. If one IP is removed and this is a virtual_server VIP then the healthcheckers corresponding will be desactivated. (and reciprocity). * Added support to "notify_up" & "notify_down" for realserver config. These options specify a script to be run according to healthchecker activity. If healthchecking fails then "notify_down" script is launched (and reciprocity for healthcheck succeed). This can be usefull for global monitoring system, to send alert to Unicenter TNG or HPOV. * Set default realserver weight to 1. So, realserver will be active if no weight is specified into the configuration file. * Review the layer4.c/tcp_socket_state to return connection in progress only if SOL_SOCKET/SO_ERROR return EINPROGRESS. Thanks go to Mark Weaver, * Reviewed the global SIGCHLD handler to not suspend execution of the calling process if status is not immediately available for one of the child processes. This remove zombies by reaping. * Extended the parser.c/set_value() code to accept encapsulated quoted string. * Review SMTP DBG() message to LOG_INFO message for more verbose error handling. * Review the check_tcp.c/check_http.c logging messages to be more detailed. * Review the check_tcp.c/check_http.c retry facility to fixes some stalled issues. * VRRP : Added support to sync_group smtp notification in addition to the per instances approach. * VRRP : Fixed some IPSEC-AH seq_num synchronizations issues. Force seq_num sync if vrrp instance is linked to a group. * VRRP : In BACKUP state, force a new MASTER election is received adv. has a lower priority as locale instance. * VRRP : vrrp.c/vrrp_state_master_rx(), sync IPSEC-AH seq_num counter (decrement) if receiving higher prio advert in MASTER state. * VRRP : Reviewed the TSM to be fully filled. Extended speed-up synchronization handling MASTER sync if group is not already synced. * VRRP : Leaving fault state, force MASTER transition is received adv priority is lower than locale. * VRRP : Extended the parser to not be borred with sync_group declaration position in the conf file. vrrp_sync_group can be declared before or after vrrp_instance. Done by adding a reverse instance lookup during parsing. * VRRP : sync_master_election cleanup. * Some cosmetics patches. * Created the keepalived/samples/keepalived.conf.SYNOPSIS to describe all keywords available. 2002-11-20 Alexandre Cassen * keepalived-0.7.6 released. * Created a common library for code modularization. This lib will be used by all Keepalived components (genhash + Keepalived) to reduce repeated and duplicated code. * Rewrote the genhash utility using the common lib. The design is similar to Keepalived core design. * Reviewed the autoconf and Makefiles for new code architecture. * Created a html utility lib for HTTP headers manipulations. * Extended the CHECK_HTTP and CHECK_SSL checkers to support remote webserver HTTP header status_code. HTTP status_code is parsed according to rfc2616.6.1. The keyword created for the new feature is "status_code" inside and "url" declaration. "status_code" feature can be mixed with "digest" feature. See the samples directory keepalived/samples/keepalived.conf.status_code for example. * Review the CHECK_HTTP and CHECK_SSL MD5SUM code to use a common stream handling function. * Matthijs van der Klip, and I fixed a bug into the HTTP/SSL code that close the socket fd even if remote webserver has not been connected. As a result of fact, next socket created were imediatly closed. As a side effect, this altered the SMTP notification when remote webserver checked fall. No SMTP notification were sent if webserver were detected DOWN. Thanks to Matthijs for time debugging and investigation. * VRRP : Rewrote the previous Gratuitous ARP facility. Created a lib (vrrp_arp.c) dealing with PF_PACKET-SOCK_RAW-ETH_P_RARP and sockaddr_ll. * VRRP : Some cosmetics patch for messages logging. * VRRP : Fixed an issue during VRRP packet building, appending VRRP VIPs to the VRRP packet in the network order form. * VRRP : Reviewed the previous VRRP packet building process to not create the ARP header. Removec the previous hacky PF_PACKET-SOCK_PACKET-0x300 to use AF_INET-SOCK_RAW-PROTO to leave kernel appending ARP header since code doesn t currently support VRRP VMAC. * VRRP : Rewrote the previous vrrp_send_pkt() function to deal with sendmsg(). optimization lazzyness :) * VRRP : Extended the interfaces library to support common utility functions (if_setsockopt_hdrincl, if_setsockopt_bindtodevice, ...) * VRRP : Finally extend the code to support VRRP IPSEC-AH authentication method. Created a IPSEC-AH seq_number syncrhonization mecanism during VRRP MASTER/BACKUP elections. * VRRP : Extended the VRRP TSM to speed up instances syncrhonization during FAULT->BACKUP & FAULT->MASTER state transition. * Some cosmetics patches. This release is proposed as a 1.0.0 STABLE release candidate. 2002-09-17 Alexandre Cassen * keepalived-0.7.1 released. * Fixed a MISC_CHECK issue when registering next timer checker. Must register a new timer thread before forking process. This imply for the user the extra script call must not execute in more than checker->vs->delay_loop. * Extented the ipfwwrapper (for LVS kernel 2.2) to not set ipchains rules if nat_mask is not specified in the configuration file. * VRRP : Added support to delayed gratuitous ARP send. When one instance enter to MASTER state a timer thread is registered. The default delay is 5secs. This delay is configurable per vrrp instance and handle the 'garp_master_delay' keyword. This delay refer to the delay after MASTER state transition we want to launch gratuitous ARP. * VRRP : Force health checker enable flag if VRRP framework is not selected. * VRRP : Review the gratuitous ARP helper function to only send gratuitous ARP if VRRP VIPs are set. * VRRP : Review the FSM to eliminate stalled flapping loop. The state transition diagram implemented is : +---------------+ +----------------| |----------------+ | | Fault | | | +------------>| |<------------+ | | | +---------------+ | | | | | | | | | V | | | | +---------------+ | | | | +--------->| |<---------+ | | | | | | Initialize | | | | | | | +-------| |-------+ | | | | | | | +---------------+ | | | | | | | | | | | | V | | V V | | V +---------------+ +---------------+ | |---------------------->| | | Master | | Backup | | |<----------------------| | +---------------+ +---------------+ The state DUMMY_MASTER state has been removed since it is a fake. * VRRP : In order to handle all possible state transition, a Transition State Matrix design (TSM) has been added. This matrix defines transition state handlers for VRRP sync group extension. The TSM implemented is (cf: vrrp_scheduler.c for more informations) : \ E | B | M | F | S \ | | | | ------+-----+-----+-----+ Legend: B | x 1 2 | B: VRRP BACKUP state ------+ | M: VRRP MASTER state M | 3 x 4 | F: VRRP FAULT state ------+ | S: VRRP start state (before transition) F | 5 6 x | E: VRRP end state (after transition) ------+-----------------+ [1..6]: Handler functions. * VRRP : Set ms_down_timer to 3 * advert_int + TIMER_SKEW when leaving MASTER state. * VRRP : In MASTER state, when incoming advert match or FAULT state is requested then force leaving MASTER state transition. (review the previous election approach). * VRRP : Optimized the leave FAULT state transition. Directly coded into the FSM for speed up recovery or code readability. * VRRP : Extended smtp notifier for BACKUP state. Review the MASTER state notification to only notify when VIPs are set. * some cosmetics patches. * Adam Fletcher, created the 'Keepalived+LVS NAT HOWTO' 2002-08-05 Alexandre Cassen * keepalived-0.6.10 released. * Fixed a faked flag during VRRP VIP set. Updated the IP address set flag to reflect netlink return code. * Fixed an autoconf issue during selection of VRRP framework. 2002-07-31 Alexandre Cassen * keepalived-0.6.9 released. * Fixe some code dependence selection during compilation. If autoconf netlink probe fails then unset VRRP code. * Cleanup daemon lib. Added some logging info for the daemon processing, removed some repeated code part. * Added 2 new daemon arguments : --dont-release-vrrp : Dont remove VRRP VIPs on daemon stop --dont-release-ipvs : Dont remove IPVS topology on daemon stop * Review the global scheduling process to clear FD queues on master thread destroy. * Fixed a forking issue in the MISC_CHECK. * Review IPVS wrapper functions to use allocated IPVS rules instead of static referencing pointer. * Fixed the IPVS wrapper to delete IPVS entries according to their 'alive' state. * Added IPVS support to alive flag for VS entries. * Rewrote the previous main.c to support configuration reload on the fly. Extented signal handling to register a conf reload_thread on SIGHUP. The software design used here is a dynamic differential conf file reloading framework. This design offer key decision to add/remove new/old entries to/from low-level framework: IPVS topology and netlink IP addresses entries. This design reduce to the max the global service interruption since only negative diff entries are removed. For VRRP config reload on the fly, if you plan to add/remove many VIPs consider VIP declaration into the virtual_ipaddress_excluded since they are not present into VRRP adverts. * Review the keepalived.init script to support restart and reload arguments. * Fixed some typo issues. 2002-07-16 Alexandre Cassen * keepalived-0.6.8 released. * Alex Kramarov, & Remi Nivet, reported an assertion error during smtp notification process. The assertion caused a bad file descriptor registration during in_progress connection handling. Fixed registering an event thread calling upper level SMTP protocol in_progress connection handler. So the SMTP stream handlers use global I/O multiplexer on connection success. * Benoit Gaussen, and I added support to "inhibit" feature. Added a new keyword called "inhibit_on_failure" for real_server declaration. If specified the real_server will not be removed from the IPVS topology if real_server fail according to checker result. Instead of removing the entry from IPVS topology, the corresponding real_server weight will be set to 0. When real_server will be back, then weight will be set back to original value. See sample directory for example. * Added support to IP_MASQ_CMD_SET_DEST for 2.2 krnl and IP_VS_SO_SET_EDITDEST for 2.4 IPVS code to provide support to "inhibit" feature. * Review Makefile.in to exit on compilation error. * Extended autconf script to check for kernel netlink support. 2002-07-12 Alexandre Cassen * keepalived-0.6.7 released. * Rewrote the previous SMTP notification framework. New code use a strong multi-threaded FSM design. * Moved the SMTP get_local_name() into utils.c * IPVS : updated the code to support IPVS_SVC_PERSISTENT_TIMEOUT. Introduced into the new libipvs coming with ipvs-1.0.4. * VRRP : Extended the mcast membership subscription to handle more robust mcast subscription errors. Removed the previous ugly stalling sleeping call retry for membership subscription. Membership subscriptions are now multi-threaded to not degrade global scheduling timer. * VRRP : Remi Nivet, pointed out a buffer overflow during the sending advert interface binding process. * Some more cosmetics patches. 2002-07-05 Alexandre Cassen * keepalived-0.6.6 released. * added indentation style .indent.pro * Review the previous source tree. Splitted the code into functional subdirs. Added multi-level automake scripts. The source tree looks like : . |-- bin |-- genhash |-- keepalived | |-- core | |-- etc | | |-- init.d | | `-- keepalived | |-- healthcheck | |-- include | |-- libipfwc | |-- libipvs | |-- samples | `-- vrrp `-- lib * Refine autoconf/automake scripts. Added automake support to libipvs and libipfwc. Added code selection compilation for libipvs and libipfwc. * Review Makefile(s) to use more convenient facilities like distclean, ... * Review the Makefile(s) code dependencies. * Added support to modprobe_ipvs if the ip_vs.o module is not loaded. If modprobe fails then IPVS is assumed unavailable. * Refine the IPVS wrapper to be more tolerant. When a VS or RS is already configured don t stop the daemon. The daemon is stopped only on critical IPVS errors. * VRRP : Review the bootstrap sequence to start daemon even if one of the instance want to run on an interface administratively shut. Added extension to FSM to force transition to FAULT state during bootstrap if the interface is shut. * Updated the TODO file. * Some cosmetics patches. 2002-07-01 Alexandre Cassen * keepalived-0.6.5 released. * Fixed a NULL pointer exception while releasing IPVS entries. * Review the Makefile.in to fixe some conventional issue. Fixed a libipvs dependance code selection. * Christophe Varoqui, created the rpm spec file. * Roberto Nibali, helped during OLS with code cleanup. Review the whole code coding style to use more conventional indentation. The one used into LVS and Kernel code. Coding style provided by the following command : find . -name "*.[chS]" -exec indent -kr -i8 -ts8 -sob -l80 -ss -bs -psl \ {} \; && find . -name "*~" -exec rm {} \; * Roberto Nibali and I review the DEBUG logging facility adding global DBG() func declaration. * Roberto Nibali fixed two potential buffer overflow (strcpy). * Richard L. Allbery, pointed out a fwmark issue. Healthcheckers is enabled if virtual service is a fwmark. * Some cosmetics patches. 2002-06-25 Alexandre Cassen * keepalived-0.6.4 released. * Rewrote the previous ip address utilities functions. Review the string to ulong convertion function to support CIDR filtering and more simple handling ("without all hexadecimal and shorthand"), pickted from Paul Vixie code. * VRRP : extended the notify framework to support scripts inside a vrrp_sync_group. view the sample/keepalived.conf.vrrp.sync file. * VRRP : Review the previous vrrp_sync_group block. New declaration is : view the sample/keepalived.conf.vrrp.sync file. * VRRP : fixed a FSM sync_group side effect in FAULT state. * Fixed a Kernel 2.2 code selection issue (ETHTOOL). * Added support to wensong libipvs. * Fixed a sorry_server cleanup side effect. * Alex Kramarov, fine the keepalived.init script to be compatible with redhat chkconfig. 2002-06-18 Alexandre Cassen * keepalived-0.6.3 released. * VRRP : Christian Motelet, pointed out a flapping issue when runing vrrp_sync_group on multiple NICs. This have been fixed adding leave FAULT state transition on both FSM state (read & read_to). The group leave fault state if all NIC of each VRRP Instance are functional. * Fixed some issue in the autoconf/automake scripts. 2002-06-16 Alexandre Cassen * keepalived-0.6.2 released. * Andres Salomon, enhanced the autoconf/automake scripts to be more generic and to facilitate cross compilation. Including more efficient IPVS code detection, Kernel version, install script location, ... * Johannes Erdfelt, fixed a genhash get request length calculation issue. * Johannes Erdfelt, fixed a wrong printed IP address issue due to a static pivot buffer called multiple times for a single syslog call. * Johannes Erdfelt, enhanced SMTP notification framework to use more compliant SMTP protocol handling. Enhanced both sending and receiving functions. A nice response code buffer handling calculating remote SMTP server retcode. * Johannes Erdfelt, fixed a NULL pointer exception into the 2.2 ipvswrapper code. * Aneesh Kumar, fixed a compilation issue for CI-LINUX checker compilation. * Jan Du Caju, fixed a compilation dependence selection into the VRRP framework when compiling without LVS support. This disable checkers activity update when compiled without LVS support. * fixed a dereferencing pointer into the parser. * move the dump configuration to printout conf after daemon initialization. * VRRP : Added support to start on complete init. VRRP framework and thus keepalived will start if VRRP instances are properly configured. 2002-06-13 Alexandre Cassen * keepalived-0.6.1 released. * Aneesh Kumar, and I added support to Cluster Infrastructure checkers. Providing HA-LVS for their cluster project (http://ci-linux.sourceforge.net/). The new checker added provide a derivation to the internal CI healthcheck mechanism. * Enhanced the Kernel netlink reflector to drive global healthcheckers activity. The policy implemented here is : If healthchecker is performing test on a service that belong to a VIP not owned by the director, then the healthchecker is suspended. This suspend/active state is particulary usefull if runing VRRP for HA => That way the backup LVS will not charge the realserver pool since LVS VIP is owned by master LVS. * Cosmetics patches into the vector lib. * VRRP : Rewrote the previous VRRP synchronization instance policy. Created a new config block called "vrrp_sync_group" that define VRRP instances synchronization dependences. That way we replace the previous "by-pair" sync approach by this "by-group" approach. This can be useefull for firewall HA with many NICs. Created a dedicated framework to speed up takeover synchronization. * VRRP : Added support to CIDR notation for VRRP VIPs definitions => VRRP VIPs definition like a.b.c.d/e. By default "e" value is set to 32. * VRRP : Added support to multicast source IP address selection => "mcast_src_ip" keyword. Can be usefull for strongly filtered env. The mcast group subscription is done using the NIC default IP after this mcast_src_ip is used if specified. * VRRP : Enhanced the link media failure detection. Added support to the new kernel SIOCETHTOOL probing for ETHTOOL_GLINK command. New drivers use this ETHTOOL interface to report link failure activity. During bootstrap a probe is done to determine the proper polling method to use for link media failure detection. The policy used is : probe for SIOCGMIIREG if not supported then try SIOCETHTOOL GLINK probe, otherwise use a ioctl SIOCGIFFLAGS polling function mirroring kernel NIC flags to localy reflected representation. * Ramon Kagan, and I updated the UserGuide.pdf. 2002-05-30 Alexandre Cassen * keepalived-0.5.9 released. * Added support to realserver_group. The work is not yet finished since it introduces new compilation design currently not supported. So please do not use yet. * VRRP : Review the script notification. Moved to a script per VRRP instance state => Created new keywords notify_backup|master|fault to run a specific script during backup|master|fault state transition. * VRRP : Added support to quoted strings for notify_backup|master|fault. Can now launch script passing arguments. See sample directory for examples. * VRRP : Added a protocol extension called "virtual_ipaddress_excluded". This configuration block is similar to "virtual_ipaddress" block => those VIPs (called E-VIPs) are set throught netlink kernel channel and gratuitous arp are sent over each E-VIP. The only difference is that they are not added into VRRP packet adverts. This can be usefull for big env where you want to run many VRRP VIPs (200 for example). VRRP packet lenght are limited to a 20 VIPs, if you want more VRRP VIPs add them to the "virtual_ipaddress_excluded" configuration block. * VRRP : Added more logging facility when setting/removings VIPs & E-VIPs. * VRRP : Created a new FSM state called become_master in charge of VIPs/E-VIPs/notifications handling. The goto_master state is now a state where the instance send an advert to force a new MASTER election setting the instance into a transition mode. If election success its finaly transit to become_master state to own VIPs/E-VIPs and launch scripts. * VRRP : Force a new MASTER election when receiving a lower prio advert. * VRRP : Review the vrrp_scheduler.c to use more conventional FSM design. This reduce and beautifull the code. * VRRP : Fixed a very noisy flapping issue observed on heavy loaded env. Simulating big traffic on a backbone figure out this flapping issue. Added support to a TIMER_MICRO_ADJUST to prevent against timer degradation. This can be view as a DOS protection policy. VRRP MASTER timers are adjusted if they are too degradated, due to heavy loaded networking env introducing latency receiving/sending VRRP protocol adverts. Thanks goes to Paul, for pointing it out and providing access to its Internet routing backbone. 2002-05-21 Alexandre Cassen * keepalived-0.5.8 released. * Added an OpenSSL Licence exception to grant Keepalived compilation with OpenSSL Toolkit. Thanks to Andres Salomon, for suggesting. * Added connection port selection for Healthcheckers (TCP_CHECK, HTTP|SSL_GET). Can be usefull for Healthcheck in fwmark LVS topology for grouping service. Thanks to Richard L. Allbery, for suggection. See samples directory for examples. * Fixed some IPVS exclusion code when running --disable-lvs. * Added support to VirtualHost selection when using HTTP|SSL_GET. See samples directory for examples. * Added VirtualHost selection into the genhash utility. * Fixed some IPVS sync daemon initializations issues. * Cometics patches in IPVS wrapper framework. * Added support to quoted string. This can be usefull if you are using MISC_CHECK and you want to pass arguments to called script. See samples. * Prepare work on real_server_group in order to group some realserver declaration. * VRRP : Fixed a password length exception causing an unwanted dropping issue. * VRRP : Enhanced the MASTER state to send gratuitous arp if receiving a remote lower prio advert => This fix a remote stalled ARP cache. Thanks to Simon Kirby, for discussing this case. 2002-05-02 Alexandre Cassen * keepalived-0.5.7 released. * Review autoconf/automake scripts to be more generic on system and code selection. Added primitives (configure) : --disable-lvs-syncd : Do not use IPVS sync daemon --disable-lvs : Do not use IPVS framework --disable-vrrp : Do not use VRRP framework --enable-debug : Compile with debugging flags * Fixed a SSL stream handling bug. Thanks to Andres Salomon, for pointing the issue. * Added a global memory counter to track global memory used. * Fixed configuration parser. read_line. Remove static allocated temporary read buffer. Only handle stream if line has been spitted into vector. * Limit maximum number of VIPs per VRRP Instance to 20. (for fragmentation, overhead, and others reasons). * Added IPVS wrapper support to persistence granularity. Thanks to Mike Zimmerman, for the suggestion. * Review smtp notifier to handle VRRP MASTER state transition alert. Thanks to Paul, for the suggestion. * Review the UserGuide.pdf to fixe some english issues :) Thanks to Jacques Thomas, for reviewing. 2002-04-13 Alexandre Cassen * keepalived-0.5.6 released. * VRRP : Review in "GOTO_MASTER_STATE" the IP address handling. send protocol adverts before registering IP address to the interface. * VRRP : Review the "LEAVE_MASTER_STATE" to only handle state transition if wanted states are BACKUP or FAULT. * VRRP : Review the BACKUP state to force new protocol election if receiving a lower priority advert. * VRRP : Fixed a BACKUP to MASTER state transition only if interface is reported UP. * VRRP : Fake the "ipvs_syncd_cmd" function if running LVS using a Kernel 2.2. 2002-04-10 Alexandre Cassen * keepalived-0.5.5 released. * Fixed a gratuitous ARP porting bug. * VRRP : Review the data structure to be more generic and clean with the rest of the code. * VRRP : Remove the interface flags (NIC) ioctl functions * VRRP : Created an interface (NIC) library giving access to common interface helpers functions. * VRRP : Created an interface lookup function creating a global interface structure during daemon bootstrap. Consist of a netlink RTM_GETLINK & RTM_GETADDR lookup, so we can work with a userspace interface representation. * VRRP : Create a netlink kernel reflection framework updating dynamically our interface structure according to kernel netlink broadcast. This design is highly inspired from zebra. => Reflection mean : wait for netlink kernel broadcast, if received, wakeup netlink filter to update our userspace representation. Prefer this design instead of a delayed netlink poller. That way we reduce global overhead. * VRRP : VRRP need to detect failure from many places. If netlink can notify for many troubles like mainly IFF_UP|DOWN & IFF_RUNNING, those flags are kernel drivers dependent. To reduce takeover time and performance we need to have informations like : Does the media link is present ?. The fact is that most of the new NICs own embended hardware chip providing such informations. So created a MII transceiver status register thread poller. Monitoring Basic Mode Status Register (BMSR) of the MII status words. Waiting for kernel NIC drivers hackers to support this functionnality through netlink (=> Like a IFF_RUNNING update broadcast). * VRRP : Linked the state machine to the global interface structure. NIC failure/events are handled. * VRRP : Review the whole state machine code to be more realistic. The State transition diagram described into the RFC2338 is an obtimist view. The VRRP state transition diagram implemented here is : +---------------+ +--------->| |<-------------+ | | Initialize | | | +------| |----------+ | | | +---------------+ | | | V V | +---------------+ +---------------+ | |---------------------->| | | Master | | Backup | | |<----------------------| | +---------------+ +---------------+ ^ | | | ^ | | | +---------------+ | | | | +------>| Dummy Master | | | | | +---------------+ | | | | | | | | | V | | | | +---------------+ | | | +------------>| |<----------+ | | | Fault | | +-----------------| |----------------+ +---------------+ * VRRP : Robust multicast handling. Something really strange is : after a NIC failure (in fallback mode) without closing the socket, multicast advert can be sent but not received ? really strange don t know why probably an IGMP resubmit ?. So multicast group is left during failover (media trouble, IFF_DOWN or !IFF_RUNNING). In fallback, we register a new membership and synchronize all the packet dispatcher fds. * VRRP : Fixed a checksum trouble using password authentication. * VRRP : Added support to the LVS sync daemon. This permit LVS sync daemon to be state drived by a specific VRRP instance. * Review the autoconf/automake to be more generic. * Some cosmetics patches. 2002-02-25 Alexandre Cassen * keepalived-0.5.3 released. * Added autoconf / automake generic scripts. * Rewrite the configuration file stream parser. Using a generic keywords tree. Each keyword refer a specific stream handler. The main stream processor is a multilevel recursive function getting file stream and backtracking the keyword tree. Kind of global compiler structure using event driven stream processing. * Re-design the global data structure to be much more generic and to dissociate LVS configuration related to checkers related. Remove static char lenght to use dynamic length strings. * Created a global timer framework. * Created a global vector template, used in cofiguration file parsing (both stream process & keywords tree generation). * Created a global list template, used in most of the code. * Review the global scheduler to remove repeated code. * Created a global checkers API. The design and goal here is to facilitate new checkers creation by localizing specific checker code into a single file without any other global framework integration. * Patched a SSL stream handling race condition finding end of stream. * Jan Holmberg, review MISC checker to use forked process to not degrade global scheduler timer. * Revisited the whole code to use new templates structures. * Fixed a url lentgh bug into the genhash utility. * Fabrice Bucher, fixed a timeout_persistence bug in the IPVS wrapper code. * Bradley McLean, added support to '0' port number service in VS manipulation. Useful for balancing all services (host rather than service). * Matthijs van der Klip, enhanced smtp framework to use SMTP header and email enclosed with angle brackets. 2001-12-20 Alexandre Cassen * keepalived-0.4.9a released. * Jan and I patched a memory pointer problems in vrrp_scheduler.c Thanks to Negrea Mihai, for reporting. * Jan Holmberg, patched a memory reallocation pointer exception in memory management framework. * Jan Holmberg, patched a vrrp vip set/remove retry. * Some cosmetics/logging patches. * Created Keepalived UserGuide. 2001-12-10 Alexandre Cassen * keepalived-0.4.9 released. * Jan Holmberg, added a memory managment framework. In debug mode it is used as a memory leak buster. We can so use it to debug quickly memory leaks (buffer overrun, allocation errors, ...). * Jan Holmberg and I added support to SSL. Checker SSL_GET. Can be used with autogenerated cert or with specific cafile, certfile, keyfile. * Use the OpenSSL, library for MD5 & SSL functions. * Jan Holmberg and I Rewrote the HTTP_GET code to use full asynchronous stream handling. The code use a common part for HTTP/SSL stream handling. Review the MD5 digest buffer computation, update MD5 over received buffer. * Patched some memory leaks in smtp handling. * Jan Holmbarg added support to LVS FWMARK. * Added command line option for keepalived. Used the libpopt library. -h, -v, -n, -d, -l, -f. * Jan Holmberg and I added debugging facility on keepalived console. * Added a BOOTSTRAP_DELAY of 1sec when registering checkers during daemon bootstrap. * VRRP : Jan Holmberg added possibility to run an extra script when VRRP Instance become or leave MASTER STATE (=> using a forked process). * Review/fine the whole code to apply cosmetics patch. * Rewrote the genhash utility. * Started checkers API specs. * doc doc doc... 2001-11-20 Alexandre Cassen * keepalived-0.4.8 released. * Rewrite the whole VRRP previous code. * VRRP : Created a hierarchic scheduling framework. Handle VRRP instances multiplexing on the same I/O fd. VRRP I/O events are handled by our global scheduling framework. Then the global sheduling framework call a VRRP I/O instance dispatcher to manage VRRP instances. * VRRP : Created a temporary socket pool to handle register our VRRP thread instances. We create & allocate a socket pool here. The soft design can be sum up by the following sketch : fd1 fd2 fd3 fd4 fdi fdi+1 -----\__/--------\__/---........---\__/--- | ETH0 | | ETH1 | | ETHn | +------+ +------+ +------+ Here we have n physical NIC. Each NIC own a maximum of 2 fds. (one for VRRP the other for IPSEC_AH). All our VRRP instances are multiplexed through this fds. So our design can handle 2*n multiplexing points. * VRRP : Review the multicast socket creating. We bind the socket to a specific NIC. inbound & outbound traffic are bound to the NIC. => why IP_ADD_MEMBERSHIP & IP_MULTICAST_IF doesnt set sk->bound_dev_if themself ??? !!! Needed for filter multicasted advert per interface. => For inbound binding we use SO_BINDTODEVICE kernel option. * VRRP : Created a read dispatcher thread to deal with our sockpool. Handle VRRP states & transition states. * VRRP : Created a VRRP synchronization instance circuit. This functionnality gave you the ability to monitor VRRP instance each other. This mean that if 2 VRRP instances are monitoring themself and if one of this instance change state, the other follow the same state. ex.: With 2 VRRP instances (VI_1 & VI_2) if VI_1 become backup then VI_2 become backup too. (symetricly with master VRRP state). * VRRP : Rewrite the netlink interface to use non blocking socket. * VRRP : Rewrite the ipaddress handling to use the new netlink interface. * VRRP : Remove the VRPP VMAC handling since linux kernel only permit to use one MAC address on a specific NIC. We use gratuitous arp when setting up VRRP VIP, to uptade remote host arp caches. => In certain case this can cause a TCP session renegociation which can cause a permature session end. => To be fully compliant with the VRRP RFC, need to patch the kernel to gave it the possibility to deal with more than one MAC address at a time. Give me clue on it please ! to same me a little time :) * Starting VRRP documentation. * Patch a pidfile handling bug when forking the keepalived daemon. Thanks goes to Gianni D'Aprile for pointing it to me. * Patch a timer race condition into the scheduling framework. This bug caused tcpcheck to respawn quickly... Thanks goes to Gianni D'Aprile for pointing it to me. 2001-11-04 Alexandre Cassen * keepalived-0.3.8 released. * Added support to native IPTABLE LVS CODE => using NAT on 2.4 kernel ipchains kernel support has been removed. * Added support to Direct Routing & Tunneling. * Review the keepalived.init script to be much more generic. 2001-09-14 Alexandre Cassen * keepalived-0.4.1 released. * Added support to LVS kernel 2.4 code 2001-08-23 Alexandre Cassen * keepalived-0.4.0 released. * Patch a race condition into the scheduler timer computation. * Patch a race condition into the tcp checker thread. Only register next timer thread if tcp connection is not in progress. * Patch a race condition into the http checker thread. Handle empty buffer returned from remote http server. * Patch a race condition into the dumping configuration process. A simple dereferencing pointer value...oops... * Eric Jarman, added MISC CHECKER. It Perform a system call to run an extra system or script. => security auditing needed for system call, buffer overflow over script path must be handled. * Added VRRP support using our scheduling I/O multiplexer. VRRP implementation support to IPSEC-AH using HMAC-96bits digest with anti-replay. rfc2402 & rfc2104. * Added routing table fetcher. We ignore route when it is a cloned route from other router, learn by an ICMP redirect or set by kernel. Only UNICAST route are stored. * Added dropping packet support. 2001-07-15 Alexandre Cassen * keepalived-0.3.5 released. * Rewrite the whole signal handling, registering a terminating thread on signal. * Move logsystem to syslog using facility LOG_INFO & LOG_DEBUG. * Added a daemonization function imported from zebra. * Rewrite the pidfile handling, check if daemon is running, if not remove eventual stalled pidfile and create new pidfile. * Added a strong scheduling framework based on an I/O multiplexer to handle asynchronous process. This code is imported from zebra and have been enhanced for keepalived purposes. Thread types are : . timeouted read on fd. . timeouted write on fd. . timer. . event. . terminate event. => The zebra framework have been enhanced to add support for timeouted read/write fds. => With this framework keepalived use a Boss/Worker thread model design, fetching ready thread from a master threading queues. * Rewrite the configuration file reader to add flexibility on extending. The dynamic data structure has been rewritten to use apropriate types. Right now parsing framework is ready for easy new checker structures integration. * Rewrite the smtp connector. The implementation take advantage of the I/O multiplexer. All read/write operations from/to the remote smtp server are done asynchronously. The implementation is rfc 821 compliant (multiple receiver are handled by a multiple RCPT TO command as specified in rfc821.3.1). * Rewrite the IPFW & IPVS wrappers. * Added support for NAT mask on IP MASQ rules (keyword nat_mask in configuration file). Added support for sorry server facility, so when all the server from a VS server pool are removed, a sorry server is automaticaly added to the VS pool (typically this is used when you have a spare server online). * Rewrite the previous checkers. Checkers are now based on a hierarchic layer stack framework. The protocol implemented for the moment is TCP. All layer 5 checkers are using layer4.c primitives with the same design : . a checker connector thread (creating the socket) registering the connection checker thread. . a connection checker thread testing connection states (error, in_progress, timeout, success). When connection success upper level thread are registered to handle checks. * Delay loop is now checkers specifics since we can use a multithreaded framework. * Update the PDF documentation file. keepalived-1.2.13/bin/0000775000175000017500000000000012334417517014304 5ustar acassenacassenkeepalived-1.2.13/bin/.gitignore0000664000175000017500000000000012211121152016237 0ustar acassenacassenkeepalived-1.2.13/VERSION0000664000175000017500000000000712334413556014600 0ustar acassenacassen1.2.13 keepalived-1.2.13/COPYING0000664000175000017500000004325412211121152014554 0ustar acassenacassen GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. keepalived-1.2.13/CONTRIBUTORS0000664000175000017500000000147612211121152015401 0ustar acassenacassenJan Holmberg, : o Memory framework o HTTP/SSL checkers Bradley Baetz, : o MISC checker redesign o Scheduler framework extension to support child process handling. o Daemon framework extension to block SIGCHLD to only receive it when its unblocked in the scheduling select loop. Jeremy Rumpf, : o Added SMTP checker Chris Caputo, : o Added dont_track_primary, nopreempt, preempt_delay, and misc_dynamic. Kevin Lindsay, : o Fixed shadowed declaration reported by -Wshadow. o Redesigned signal handling. Nick Couchman, : o Patch for u_threshold and l_threshold support. Willy Tarreau, : o Extended VRRP framework to support floating priority. keepalived-1.2.13/keepalived/0000775000175000017500000000000012334417517015645 5ustar acassenacassenkeepalived-1.2.13/keepalived/Makefile.in0000664000175000017500000000544312211121152017675 0ustar acassenacassen# Makefile # # Keepalived OpenSource project. # # Copyright (C) 2001-2012 Alexandre Cassen, EXEC = keepalived BIN = ../bin KERNEL = @KERN@ IPVS_FLAG = @IPVS_SUPPORT@ VRRP_FLAG = @VRRP_SUPPORT@ prefix = @prefix@ exec_prefix = @exec_prefix@ sbindir = @sbindir@ sysconfdir = @sysconfdir@ datarootdir = @datarootdir@ mandir = @mandir@ init_dir = $(sysconfdir)/rc.d/init.d conf_dir = $(sysconfdir)/keepalived sysconf_dir = $(sysconfdir)/sysconfig CC = @CC@ STRIP = @STRIP@ LDFLAGS = @LIBS@ @LDFLAGS@ -ldl SUBDIRS = core ifeq ($(IPVS_FLAG),_WITH_LVS_) SUBDIRS += check endif ifeq ($(VRRP_FLAG),_WITH_VRRP_) SUBDIRS += vrrp endif ifeq ($(IPVS_FLAG),_WITH_LVS_) ifeq ($(KERNEL),_KRNL_2_4_) SUBDIRS += libipvs-2.4 else SUBDIRS += libipvs-2.6 endif endif all: @set -e; \ for i in $(SUBDIRS); do \ $(MAKE) -C $$i || exit 1; done && \ echo "Building $(BIN)/$(EXEC)" && \ $(CC) -o $(BIN)/$(EXEC) `find $(SUBDIRS) ../lib -name '*.[oa]'` $(LDFLAGS) $(STRIP) $(BIN)/$(EXEC) @echo "" @echo "Make complete" debug: @set -e; \ for i in $(SUBDIRS); do \ $(MAKE) -C $$i || exit 1; done && \ echo "Building $(BIN)/$(EXEC)" && \ $(CC) -o $(BIN)/$(EXEC) `find $(SUBDIRS) ../lib -name '*.[oa]'` $(LDFLAGS) -ggdb @echo "" @echo "Make complete" profile: @set -e; \ for i in $(SUBDIRS); do \ $(MAKE) -C $$i || exit 1; done && \ echo "Building $(BIN)/$(EXEC)" && \ $(CC) -o $(BIN)/$(EXEC) `find $(SUBDIRS) ../lib -name '*.[oa]'` $(LDFLAGS) -pg @echo "" @echo "Make complete" clean: @set -e; \ for i in $(SUBDIRS); do \ $(MAKE) -C $$i clean; done @echo "" @echo "Make complete" distclean: @set -e; \ for i in $(SUBDIRS); do \ $(MAKE) -C $$i distclean; done rm -f Makefile $(BIN)/$(EXEC) mrproper: distclean rm -f config.* uninstall: rm -f $(DESTDIR)$(sbindir)/$(EXEC) rm -f $(DESTDIR)$(init_dir)/keepalived.init rm -f $(DESTDIR)$(sysconf_dir)/keepalived rm -rf $(DESTDIR)$(sysconfdir)/keepalived rm -f $(DESTDIR)$(mandir)/man/man5/keepalived.conf.5 rm -f $(DESTDIR)$(mandir)/man/man8/keepalived.8 install: install -d $(DESTDIR)$(sbindir) install -m 700 $(BIN)/$(EXEC) $(DESTDIR)$(sbindir)/ install -d $(DESTDIR)$(init_dir) install -m 755 etc/init.d/keepalived.init $(DESTDIR)$(init_dir)/keepalived install -d $(DESTDIR)$(sysconf_dir) install -m 755 etc/init.d/keepalived.sysconfig $(DESTDIR)$(sysconf_dir)/keepalived install -d $(DESTDIR)$(sysconfdir)/keepalived/samples install -m 644 etc/keepalived/keepalived.conf $(DESTDIR)$(sysconfdir)/keepalived/ install -m 644 ../doc/samples/* $(DESTDIR)$(sysconfdir)/keepalived/samples/ install -d $(DESTDIR)$(mandir)/man5 install -d $(DESTDIR)$(mandir)/man8 install -m 644 ../doc/man/man5/keepalived.conf.5 $(DESTDIR)$(mandir)/man5 install -m 644 ../doc/man/man8/keepalived.8 $(DESTDIR)$(mandir)/man8 keepalived-1.2.13/keepalived/libipvs-2.4/0000775000175000017500000000000012211121152017573 5ustar acassenacassenkeepalived-1.2.13/keepalived/libipvs-2.4/Makefile.in0000664000175000017500000000036212211121152021641 0ustar acassenacassen# Makefile to make libipvsc. CC = @CC@ CFLAGS = @CFLAGS@ @CPPFLAGS@ -Wall -Wunused export OBJS += libipvs.a all: libipvs.a libipvs.a: libipvs.a(libipvs.o) libipvsc.o: libipvs.h clean: rm -f *.a *.o *~ distclean: clean rm -f Makefile keepalived-1.2.13/keepalived/libipvs-2.4/libipvs.h0000664000175000017500000000350012211121152021412 0ustar acassenacassen/* * libipvs.h: header file for the library ipvs * * Version: $Id: libipvs.h,v 1.3 2002/07/09 14:41:19 wensong Exp $ * * Authors: Wensong Zhang * */ #ifndef _LIBIPVS_H #define _LIBIPVS_H #include /* * 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) /* 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); /* set command */ extern int ipvs_command(int cmd, struct ip_vs_rule_user *urule); /* get all the ipvs services */ extern struct ip_vs_get_services *ipvs_get_services(void); /* get the destination array of the specified service */ extern struct ip_vs_get_dests *ipvs_get_dests(struct ip_vs_service_user *svc); /* get ipvs service */ extern struct ip_vs_service_user * ipvs_get_service(u_int32_t fwmark, u_int16_t protocol, u_int32_t vaddr, u_int16_t vport); /* get ipvs timeout */ extern struct ip_vs_timeout_user *ipvs_get_timeouts(void); /* get ipvs daemon information */ extern struct ip_vs_daemon_user *ipvs_get_daemon(void); /* close the socket */ extern void ipvs_close(void); extern const char *ipvs_strerror(int err); #endif /* _LIBIPVS_H */ keepalived-1.2.13/keepalived/libipvs-2.4/libipvs.c0000664000175000017500000001271112211121152021411 0ustar acassenacassen/* * libipvs: Library for manipulating IPVS through [gs]etsockopt * * Version: $Id: libipvs.c,v 1.4 2001/11/23 14:34:17 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" #define SET_CMD(cmd) (cmd - IP_VS_BASE_CTL) #define GET_CMD(cmd) (cmd - IP_VS_BASE_CTL + 128) static int sockfd = -1; static int ipvs_cmd = 0; struct ip_vs_getinfo ipvs_info; int ipvs_init(void) { socklen_t len; len = sizeof(ipvs_info); if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) return -1; ipvs_cmd = GET_CMD(IP_VS_SO_GET_INFO); if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_INFO, (char *)&ipvs_info, &len)) return -1; return 0; } int ipvs_getinfo(void) { socklen_t len; len = sizeof(ipvs_info); ipvs_cmd = GET_CMD(IP_VS_SO_GET_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_command(int cmd, struct ip_vs_rule_user *urule) { ipvs_cmd = SET_CMD(cmd); return setsockopt(sockfd, IPPROTO_IP, cmd, (char *)urule, sizeof(*urule)); } struct ip_vs_get_services *ipvs_get_services(void) { struct ip_vs_get_services *get; socklen_t len; len = sizeof(*get) + sizeof(struct ip_vs_service_user)*ipvs_info.num_services; if (!(get = malloc(len))) return NULL; ipvs_cmd = GET_CMD(IP_VS_SO_GET_SERVICES); get->num_services = ipvs_info.num_services; if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_SERVICES, get, &len) < 0) { free(get); return NULL; } return get; } struct ip_vs_get_dests *ipvs_get_dests(struct ip_vs_service_user *svc) { struct ip_vs_get_dests *d; socklen_t len; len = sizeof(*d) + sizeof(struct ip_vs_dest_user)*svc->num_dests; if (!(d = malloc(len))) return NULL; ipvs_cmd = GET_CMD(IP_VS_SO_GET_DESTS); d->fwmark = svc->fwmark; d->protocol = svc->protocol; d->addr = svc->addr; d->port = svc->port; d->num_dests = svc->num_dests; if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_DESTS, d, &len) < 0) { free(d); return NULL; } return d; } struct ip_vs_service_user * ipvs_get_service(u_int32_t fwmark, u_int16_t protocol, u_int32_t vaddr, u_int16_t vport) { struct ip_vs_service_user *svc; socklen_t len; len = sizeof(*svc); if (!(svc = malloc(len))) return NULL; ipvs_cmd = GET_CMD(IP_VS_SO_GET_SERVICE); svc->fwmark = fwmark; svc->protocol = protocol; svc->addr = vaddr; svc->port = vport; if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_SERVICE, (char *)svc, &len)) { free(svc); return NULL; } return svc; } struct ip_vs_timeout_user *ipvs_get_timeouts(void) { struct ip_vs_timeout_user *u; socklen_t len; len = sizeof(*u); if (!(u = malloc(len))) return NULL; ipvs_cmd = GET_CMD(IP_VS_SO_GET_TIMEOUTS); if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_TIMEOUTS, (char *)u, &len)) { free(u); return NULL; } return u; } struct ip_vs_daemon_user *ipvs_get_daemon(void) { struct ip_vs_daemon_user *u; socklen_t len; len = sizeof(*u); if (!(u = malloc(len))) return NULL; ipvs_cmd = GET_CMD(IP_VS_SO_GET_DAEMON); if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_DAEMON, (char *)u, &len)) { free(u); return NULL; } return u; } void ipvs_close(void) { close(sockfd); } const char *ipvs_strerror(int err) { unsigned int i; struct table_struct { int cmd; int err; const char *message; } table [] = { { 0, EPERM, "Permission denied (you must be root)" }, { 0, EINVAL, "Module is wrong version" }, { 0, ENOPROTOOPT, "Protocol not available" }, { 0, ENOMEM, "Memory allocation problem" }, { SET_CMD(IP_VS_SO_SET_ADD), EEXIST, "Service already exists" }, { SET_CMD(IP_VS_SO_SET_ADD), ENOENT, "Scheduler not found" }, { SET_CMD(IP_VS_SO_SET_EDIT), ESRCH, "No such service" }, { SET_CMD(IP_VS_SO_SET_EDIT), ENOENT, "Scheduler not found" }, { SET_CMD(IP_VS_SO_SET_DEL), ESRCH, "No such service" }, { SET_CMD(IP_VS_SO_SET_ADDDEST), ESRCH, "Service not defined" }, { SET_CMD(IP_VS_SO_SET_ADDDEST), EEXIST, "Destination already exists" }, { SET_CMD(IP_VS_SO_SET_EDITDEST), ESRCH, "Service not defined" }, { SET_CMD(IP_VS_SO_SET_EDITDEST), ENOENT, "No such destination" }, { SET_CMD(IP_VS_SO_SET_DELDEST), ESRCH, "Service not defined" }, { SET_CMD(IP_VS_SO_SET_DELDEST), ENOENT, "No such destination" }, { SET_CMD(IP_VS_SO_SET_STARTDAEMON), EEXIST, "Daemon has already run" }, { SET_CMD(IP_VS_SO_SET_STOPDAEMON), ESRCH, "No daemon is running" }, { SET_CMD(IP_VS_SO_SET_STOPDAEMON), ESRCH, "No daemon is running" }, { SET_CMD(IP_VS_SO_SET_ZERO), ESRCH, "No such service" }, { GET_CMD(IP_VS_SO_GET_SERVICE), ESRCH, "No such service" }, { GET_CMD(IP_VS_SO_GET_DESTS), ESRCH, "No such service" }, }; for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { if ((!table[i].cmd || table[i].cmd == ipvs_cmd) && table[i].err == err) return table[i].message; } return strerror(err); } keepalived-1.2.13/keepalived/etc/0000775000175000017500000000000012211121152016375 5ustar acassenacassenkeepalived-1.2.13/keepalived/etc/init.d/0000775000175000017500000000000012211121152017562 5ustar acassenacassenkeepalived-1.2.13/keepalived/etc/init.d/keepalived.init0000775000175000017500000000243412211121152022566 0ustar acassenacassen#!/bin/sh # # Startup script for the Keepalived daemon # # processname: keepalived # pidfile: /var/run/keepalived.pid # config: /etc/keepalived/keepalived.conf # chkconfig: - 21 79 # description: Start and stop Keepalived # Source function library . /etc/rc.d/init.d/functions # Source configuration file (we set KEEPALIVED_OPTIONS there) . /etc/sysconfig/keepalived RETVAL=0 prog="keepalived" start() { echo -n $"Starting $prog: " daemon keepalived ${KEEPALIVED_OPTIONS} RETVAL=$? echo [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$prog } stop() { echo -n $"Stopping $prog: " killproc keepalived RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$prog } reload() { echo -n $"Reloading $prog: " killproc keepalived -1 RETVAL=$? echo } # See how we were called. case "$1" in start) start ;; stop) stop ;; reload) reload ;; restart) stop start ;; condrestart) if [ -f /var/lock/subsys/$prog ]; then stop start fi ;; status) status keepalived RETVAL=$? ;; *) echo "Usage: $0 {start|stop|reload|restart|condrestart|status}" RETVAL=1 esac exit $RETVAL keepalived-1.2.13/keepalived/etc/init.d/keepalived.sysconfig0000664000175000017500000000123312211121152023620 0ustar acassenacassen# Options for keepalived. See `keepalived --help' output and keepalived(8) and # keepalived.conf(5) man pages for a list of all options. Here are the most # common ones : # # --vrrp -P Only run with VRRP subsystem. # --check -C Only run with Health-checker subsystem. # --dont-release-vrrp -V Dont remove VRRP VIPs & VROUTEs on daemon stop. # --dont-release-ipvs -I Dont remove IPVS topology on daemon stop. # --dump-conf -d Dump the configuration data. # --log-detail -D Detailed log messages. # --log-facility -S 0-7 Set local syslog facility (default=LOG_DAEMON) # KEEPALIVED_OPTIONS="-D" keepalived-1.2.13/keepalived/etc/init.d/keepalived.rh.init0000775000175000017500000000235212211121152023175 0ustar acassenacassen#!/bin/sh # # Startup script for the Keepalived daemon # # processname: keepalived # pidfile: /var/run/keepalived.pid # config: /etc/keepalived/keepalived.conf # chkconfig: 35 21 79 # description: Start and stop Keepalived # Global definitions PID_FILE="/var/run/keepalived.pid" # source function library . /etc/init.d/functions RETVAL=0 start() { echo -n "Starting Keepalived for LVS: " daemon keepalived -D RETVAL=$? echo [ $RETVAL -eq 0 ] && touch /var/lock/subsys/keepalived return $RETVAL } stop() { echo -n "Shutting down Keepalived for LVS: " killproc keepalived RETVAL=0 echo [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/keepalived return $RETVAL } reload() { echo -n "Reloading Keepalived config: " killproc keepalived -1 RETVAL=$? echo return $RETVAL } # See how we were called. case "$1" in start) start ;; stop) stop ;; restart) stop start ;; reload) reload ;; status) status keepalived ;; condrestart) [ -f /var/lock/subsys/keepalived ] && $0 restart || : ;; *) echo "Usage: $0 {start|stop|restart|reload|condrestart|status}" exit 1 esac exit 0 keepalived-1.2.13/keepalived/etc/init.d/keepalived.suse.init0000664000175000017500000000740112211121152023540 0ustar acassenacassen#! /bin/sh ### BEGIN INIT INFO # Provides: keepalived # Required-Start: $remote_fs $syslog # Required-Stop : $remote_fs $syslog # Default-Start : 3 5 # Default-Stop : 0 1 2 6 # Description : Start keepalived to allow XY and provide YZ # continued on second line by '#' ### END INIT INFO DAEMON="Keepalived daemon" DAEMON_BIN="/usr/local/sbin/keepalived" DAEMON_CONF="/etc/keepalived/keepalived.conf" DAEMON_PIDFILE="/var/run/keepalived.pid" DAEMON_OPT="-d" #DAEMON_USER="root" SUPPORTS_HUP="yes" # "yes" if exist next values in freshclam.conf # PidFile /var/run/keepalived.pid # DatabaseOwner root pid_par=${DAEMON_PIDFILE:+"-p $DAEMON_PIDFILE"} usr_par=${DAEMON_USER:+"-u $DAEMON_USER"} test -x $DAEMON_BIN || exit 5 # Shell functions sourced from /etc/rc.status: # rc_check check and set local and overall rc status # rc_status check and set local and overall rc status # rc_status -v ditto but be verbose in local rc status # rc_status -v -r ditto and clear the local rc status # rc_failed set local and overall rc status to failed # rc_failed set local and overall rc status to # rc_reset clear local rc status (overall remains) # rc_exit exit appropriate to overall rc status . /etc/rc.status # First reset status of this service rc_reset # Return values acc. to LSB for all commands but status: # 0 - success # 1 - generic or unspecified error # 2 - invalid or excess argument(s) # 3 - unimplemented feature (e.g. "reload") # 4 - insufficient privilege # 5 - program is not installed # 6 - program is not configured # 7 - program is not running # # Note that starting an already running service, stopping # or restarting a not-running service as well as the restart # with force-reload (in case signalling is not supported) are # considered a success. # remove empty pid files to avoid disturbing warnings by checkproc/killproc # (these can occur if dhcpd does not start correctly) test -e $DAEMON_PIDFILE && ! test -s $DAEMON_PIDFILE && rm $DAEMON_PIDFILE case "$1" in start) echo -n "Starting $DAEMON " if test ! -f ${DAEMON_CONF}; then echo -n >&2 "Configuration file, ${DAEMON_CONF} does not exist. " rc_status -s exit 6 fi checkproc $pid_par ${DAEMON_BIN} case $? in 0) echo -n "- Warning: daemon already running. " ;; 1) echo -n "- Warning: ${DAEMON_PIDFILE} exists. " ;; esac # echo "startproc $usr_par $pid_par ${DAEMON_BIN} ${DAEMON_OPT}" startproc $usr_par $pid_par ${DAEMON_BIN} ${DAEMON_OPT} rc_status -v ;; stop) echo -n "Shutting down $DAEMON " checkproc $pid_par ${DAEMON_BIN} || \ echo -n " Warning: daemon not running. " killproc $pid_par -t 10 ${DAEMON_BIN} rc_status -v ;; try-restart|condrestart) if test "$1" = "condrestart"; then echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}" fi $0 status if test $? = 0; then $0 restart else rc_reset fi rc_status ;; restart) $0 stop $0 start rc_status ;; force-reload|reload) if test "$SUPPORTS_HUP" = "yes"; then echo -n "Reload service $DAEMON " checkproc $pid_par ${DAEMON_BIN} && \ touch ${DAEMON_PIDFILE} || \ echo -n >&2 " Warning: daemon not running. " killproc $pid_par -HUP ${DAEMON_BIN} rc_status -v else $0 stop && sleep 3 && $0 start rc_status fi ;; status) echo -n "Checking for $DAEMON " checkproc $pid_par ${DAEMON_BIN} rc_status -v ;; probe) test ${DAEMON_CONF} -nt ${DAEMON_PIDFILE} && echo reload ;; *) echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}" exit 1 ;; esac rc_exit keepalived-1.2.13/keepalived/etc/keepalived/0000775000175000017500000000000012211121152020506 5ustar acassenacassenkeepalived-1.2.13/keepalived/etc/keepalived/keepalived.conf0000664000175000017500000000675212211121152023500 0ustar acassenacassen! Configuration File for keepalived global_defs { notification_email { acassen@firewall.loc failover@firewall.loc sysadmin@firewall.loc } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 192.168.200.1 smtp_connect_timeout 30 router_id LVS_DEVEL } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.200.16 192.168.200.17 192.168.200.18 } } virtual_server 192.168.200.100 443 { delay_loop 6 lb_algo rr lb_kind NAT nat_mask 255.255.255.0 persistence_timeout 50 protocol TCP real_server 192.168.201.100 443 { weight 1 SSL_GET { url { path / digest ff20ad2481f97b1754ef3e12ecd3a9cc } url { path /mrtg/ digest 9b3a0c85a887a256d6939da88aabd8cd } connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } } virtual_server 10.10.10.2 1358 { delay_loop 6 lb_algo rr lb_kind NAT persistence_timeout 50 protocol TCP sorry_server 192.168.200.200 1358 real_server 192.168.200.2 1358 { weight 1 HTTP_GET { url { path /testurl/test.jsp digest 640205b7b0fc66c1ea91c463fac6334d } url { path /testurl2/test.jsp digest 640205b7b0fc66c1ea91c463fac6334d } url { path /testurl3/test.jsp digest 640205b7b0fc66c1ea91c463fac6334d } connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } real_server 192.168.200.3 1358 { weight 1 HTTP_GET { url { path /testurl/test.jsp digest 640205b7b0fc66c1ea91c463fac6334c } url { path /testurl2/test.jsp digest 640205b7b0fc66c1ea91c463fac6334c } connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } } virtual_server 10.10.10.3 1358 { delay_loop 3 lb_algo rr lb_kind NAT nat_mask 255.255.255.0 persistence_timeout 50 protocol TCP real_server 192.168.200.4 1358 { weight 1 HTTP_GET { url { path /testurl/test.jsp digest 640205b7b0fc66c1ea91c463fac6334d } url { path /testurl2/test.jsp digest 640205b7b0fc66c1ea91c463fac6334d } url { path /testurl3/test.jsp digest 640205b7b0fc66c1ea91c463fac6334d } connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } real_server 192.168.200.5 1358 { weight 1 HTTP_GET { url { path /testurl/test.jsp digest 640205b7b0fc66c1ea91c463fac6334d } url { path /testurl2/test.jsp digest 640205b7b0fc66c1ea91c463fac6334d } url { path /testurl3/test.jsp digest 640205b7b0fc66c1ea91c463fac6334d } connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } } keepalived-1.2.13/keepalived/libipvs-2.6/0000775000175000017500000000000012334417517017620 5ustar acassenacassenkeepalived-1.2.13/keepalived/libipvs-2.6/Makefile.in0000664000175000017500000000053412263015244021657 0ustar acassenacassen# Makefile for libipvs CC = @CC@ CFLAGS = @CFLAGS@ @CPPFLAGS@ -D@USE_NL@ -Wall -Wunused export OBJS += libipvs.a STATIC_LIB = libipvs.a all: $(STATIC_LIB) $(STATIC_LIB): libipvs.o ip_vs_nl_policy.o ar rv $@ $^ rm $^ %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< clean: rm -f *.[ao] *~ *.orig *.rej core distclean: clean rm -f Makefile keepalived-1.2.13/keepalived/libipvs-2.6/ip_vs.h0000644000175000017500000003673512262726124021122 0ustar acassenacassen/* * IP Virtual Server * data structure and functionality definitions */ #ifndef _IP_VS_H #define _IP_VS_H #include #include #include #ifdef LIBIPVS_USE_NL #include #include #include #endif /* Userland compatibility with kernel */ #define __u32 u_int32_t #define __be32 u_int32_t #define __u16 u_int16_t #define __be16 u_int16_t #define __u64 u_int64_t #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 */ #define IP_VS_SVC_F_SCHED1 0x0008 /* scheduler flag 1 */ #define IP_VS_SVC_F_SCHED2 0x0010 /* scheduler flag 2 */ #define IP_VS_SVC_F_SCHED3 0x0020 /* scheduler flag 3 */ #define IP_VS_SVC_F_SCHED_SH_FALLBACK IP_VS_SVC_F_SCHED1 /* SH fallback */ #define IP_VS_SVC_F_SCHED_SH_PORT IP_VS_SVC_F_SCHED2 /* SH use port */ /* * 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_CMD_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 */ #undef __u32 #undef __be32 #undef __u16 #undef __be16 #undef __u64 #endif /* _IP_VS_H */ keepalived-1.2.13/keepalived/libipvs-2.6/libipvs.h0000644000175000017500000000746512245104631021442 0ustar acassenacassen/* * 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(u_int32_t, u_int16_t, u_int16_t, union nf_inet_addr, u_int16_t); /* 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 */ keepalived-1.2.13/keepalived/libipvs-2.6/libipvs.c0000644000175000017500000007361012262526326021440 0ustar acassenacassen/* * 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 #ifdef FALLBACK_LIBNL1 #define nl_sock nl_handle #define nl_socket_alloc nl_handle_alloc #define nl_socket_free nl_handle_destroy #endif static struct nl_sock *sock = NULL; static int family, try_nl = 1; #endif #define CHECK_IPV4(s, ret) if (s->af && s->af != AF_INET) \ { errno = EAFNOSUPPORT; goto out_err; } \ s->__addr_v4 = s->addr.ip; \ #define CHECK_PE(s, ret) if (s->pe_name[0]) \ { errno = EAFNOSUPPORT; goto out_err; } #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 #ifndef FALLBACK_LIBNL1 static int nlerr2syserr(int err) { switch (abs(err)) { case NLE_BAD_SOCK: return EBADF; case NLE_EXIST: return EEXIST; case NLE_NOADDR: return EADDRNOTAVAIL; case NLE_OBJ_NOTFOUND: return ENOENT; case NLE_INTR: return EINTR; case NLE_AGAIN: return EAGAIN; case NLE_INVAL: return EINVAL; case NLE_NOACCESS: return EACCES; case NLE_NOMEM: return ENOMEM; case NLE_AF_NOSUPPORT: return EAFNOSUPPORT; case NLE_PROTO_MISMATCH: return EPROTONOSUPPORT; case NLE_OPNOTSUPP: return EOPNOTSUPP; case NLE_PERM: return EPERM; case NLE_BUSY: return EBUSY; case NLE_RANGE: return ERANGE; case NLE_NODEV: return ENODEV; default: return err; } } #endif 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_socket_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_socket_free(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_socket_free(sock); return 0; fail_genl: nl_socket_free(sock); sock = NULL; nlmsg_free(msg); errno = err; #ifndef FALLBACK_LIBNL1 errno = nlerr2syserr(err); #endif return -1; } #endif int ipvs_init(void) { socklen_t len; ipvs_func = ipvs_init; #ifdef LIBIPVS_USE_NL try_nl = 1; 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[0]) 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)); out_err: return -1; } 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)); out_err: return -1; } 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)); out_err: return -1; } 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)); out_err: return -1; } #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)); out_err: return -1; } 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)); out_err: return -1; } 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)); out_err: return -1; } 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))) { free(get); 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_CMD_ATTR_MAX + 1]; struct nlattr *dest_attrs[IPVS_DEST_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))) { free(d); 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(u_int32_t fwmark, u_int16_t af, u_int16_t protocol, union nf_inet_addr addr, u_int16_t port) { ipvs_service_entry_t *svc; socklen_t len; ipvs_func = ipvs_get_service; #ifdef LIBIPVS_USE_NL if (try_nl) { struct ip_vs_get_services *get; struct nl_msg *msg; ipvs_service_t tsvc; svc = malloc(sizeof(*svc)); if (!svc) return NULL; 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 len = sizeof(*svc); svc = calloc(1, len); if (!svc) return NULL; svc->fwmark = fwmark; svc->af = af; svc->protocol = protocol; svc->addr = addr; svc->port = port; CHECK_COMPAT_SVC(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; out_err: free(svc); return NULL; } #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); } keepalived-1.2.13/keepalived/libipvs-2.6/ip_vs_nl_policy.c0000644000175000017500000000542112245104631023143 0ustar acassenacassen#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 */ keepalived-1.2.13/keepalived/include/0000775000175000017500000000000012334225741017264 5ustar acassenacassenkeepalived-1.2.13/keepalived/include/vrrp_ipsecah.h0000664000175000017500000000436712211121152022115 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vrrp_ipsecah.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_IPSEC_AH_H #define _VRRP_IPSEC_AH_H #include #include #include #include #include /* Predefined values */ #define HMAC_MD5_TRUNC 0x0C /* MD5 digest truncate value : 96-bit -- rfc2403.2 & rfc2104.5 */ #define IPSEC_AH_PLEN 0x04 /* Const for a 96-bit auth value : Computed in 32-bit words minus 2 => (HMAC_MD5_TRUNC*8+3*32)/32 - 2 -- rfc2402.2.2 */ #define IPPROTO_IPSEC_AH 51 /* IP protocol number -- rfc2402.2 */ typedef struct _ipsec_ah { /* rfc2402.2 */ uint8_t next_header; /* Next header field */ uint8_t payload_len; /* Payload Lenght */ uint16_t reserved; /* Reserved field */ uint32_t spi; /* Security Parameter Index */ uint32_t seq_number; /* Sequence number */ uint32_t auth_data[3]; /* Authentication data 128-bit MD5 digest trucated => HMAC_MD5_TRUNC*8/32 */ } ipsec_ah_t; typedef struct { /* rfc2402.3.3.3.1.1.1 */ uint8_t tos; uint16_t frag_off; uint16_t check; } ICV_mutable_fields; /* We need to zero this fields to compute the ICV */ typedef struct _seq_counter { int cycle; uint32_t seq_number; } seq_counter_t; extern void hmac_md5(unsigned char *, int, unsigned char *, int, unsigned char *); #endif keepalived-1.2.13/keepalived/include/smtp.h0000664000175000017500000000512712211121152020406 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: smtp.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _SMTP_H #define _SMTP_H /* globales includes */ #include /* local includes */ #include "check_data.h" #include "vrrp_data.h" #include "scheduler.h" #include "layer4.h" #include "vrrp.h" /* global defs */ #define SMTP_PORT_STR "25" #define SMTP_PORT 25 #define SMTP_BUFFER_LENGTH 512 #define SMTP_BUFFER_MAX 1024 #define SMTP_MAX_FSM_STATE 10 #define SMTP_EMAIL_ADDR_MAX_LENGTH 64 /* SMTP command stage */ #define HELO 4 #define MAIL 5 #define RCPT 6 #define DATA 7 #define BODY 8 #define QUIT 9 #define END 10 #define ERROR 11 /* SMTP thread argument structure */ #define MAX_HEADERS_LENGTH 256 #define MAX_BODY_LENGTH 512 /* SMTP FSM Macro */ #define SMTP_FSM_SEND(S, T) \ do { \ if ((*(SMTP_FSM[S].send))) \ (*(SMTP_FSM[S].send)) (T); \ } while (0) #define SMTP_FSM_READ(S, T, N) \ do { \ if ((*(SMTP_FSM[S].read))) \ (*(SMTP_FSM[S].read)) (T, N); \ } while (0) /* SMTP thread arguments */ typedef struct _smtp { int fd; int stage; int email_it; char *subject; char *body; char *buffer; char *email_to; long buflen; } smtp_t; /* SMTP command string processing */ #define SMTP_HELO_CMD "HELO %s\r\n" #define SMTP_MAIL_CMD "MAIL FROM:<%s>\r\n" #define SMTP_RCPT_CMD "RCPT TO:<%s>\r\n" #define SMTP_DATA_CMD "DATA\r\n" #define SMTP_HEADERS_CMD "Date: %s\r\nFrom: %s\r\nSubject: %s\r\n" \ "X-Mailer: Keepalived\r\nTo: %s\r\n\r\n" #define SMTP_BODY_CMD "%s\r\n" #define SMTP_SEND_CMD "\r\n.\r\n" #define SMTP_QUIT_CMD "QUIT\r\n" /* Prototypes defs */ extern void smtp_alert(real_server_t *, vrrp_t *, vrrp_sgroup_t *, const char *, const char *); #endif keepalived-1.2.13/keepalived/include/check_misc.h0000664000175000017500000000265712211121152021520 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: check_misc.c include file. * * Author: Alexandre Cassen, * Eric Jarman, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _CHECK_MISC_H #define _CHECK_MISC_H /* system includes */ #include /* local includes */ #include "scheduler.h" /* Checker argument structure */ typedef struct _misc_checker { char *path; long timeout; int dynamic; /* 0: old-style, 1: exit code from checker affects weight */ } misc_checker_t; /* Prototypes defs */ extern void install_misc_check_keyword(void); #endif keepalived-1.2.13/keepalived/include/check_smtp.h0000644000175000017500000000420212334072037021547 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: check_smtp.c include file. * * Author: Alexandre Cassen, * Jeremy Rumpf, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _CHECK_SMTP_H #define _CHECK_SMTP_H /* system includes */ #include /* local includes */ #include "check_data.h" #include "scheduler.h" #include "list.h" #include "check_api.h" #define SMTP_BUFF_MAX 512 #define SMTP_START 1 #define SMTP_HAVE_BANNER 2 #define SMTP_SENT_HELO 3 #define SMTP_RECV_HELO 4 #define SMTP_SENT_QUIT 5 #define SMTP_RECV_QUIT 6 #define SMTP_DEFAULT_HELO "smtpchecker.keepalived.org" #define SMTP_DEFAULT_PORT 25 /* Per host configuration structure */ typedef conn_opts_t smtp_host_t; /* Checker argument structure */ typedef struct _smtp_checker { /* non per host config data goes here */ char *helo_name; long timeout; long db_retry; int retry; int attempts; int host_ctr; smtp_host_t *host_ptr; /* data buffer */ char buff[SMTP_BUFF_MAX]; int buff_ctr; int (*buff_cb) (thread_t *); int state; /* list holding the host config data */ list host; } smtp_checker_t; /* macro utility */ #define FMT_SMTP_RS(H) (inet_sockaddrtopair (&(H)->dst)) /* Prototypes defs */ extern void install_smtp_check_keyword(void); #endif keepalived-1.2.13/keepalived/include/vrrp_iproute.h0000664000175000017500000000445012211337771022201 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vrrp_iproute.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_IPROUTE_H #define _VRRP_IPROUTE_H /* global includes */ #include #include #include /* local includes */ #include "list.h" #include "vector.h" /* types definition */ typedef struct _ip_route { ip_address_t *dst; /* RTA_DST */ uint8_t dmask; ip_address_t *gw; /* RTA_GATEWAY */ ip_address_t *gw2; /* Will use RTA_MULTIPATH */ ip_address_t *src; /* RTA_PREFSRC */ uint32_t metric; /* RTA_PRIORITY */ int index; /* RTA_OIF */ int blackhole; int scope; int table; int set; } ip_route_t; #define IPROUTE_DEL 0 #define IPROUTE_ADD 1 /* Macro definition */ #define ROUTE_ISEQ(X,Y) (IP_ISEQ((X)->dst, (Y)->dst) && \ (X)->dmask == (Y)->dmask && \ IP_ISEQ((X)->gw, (Y)->gw) && \ IP_ISEQ((X)->src, (Y)->src) && \ (X)->table == (Y)->table && \ (X)->scope == (Y)->scope && \ (X)->index == (Y)->index) /* prototypes */ extern int netlink_route(ip_route_t *, int); extern void netlink_rtlist(list, int); extern void free_iproute(void *); extern void dump_iproute(void *); extern void alloc_route(list, vector_t *); extern void clear_diff_routes(list, list); extern void clear_diff_sroutes(void); #endif keepalived-1.2.13/keepalived/include/check_daemon.h0000664000175000017500000000243612211121152022023 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: check_daemon.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _CHECK_DAEMON_H #define _CHECK_DAEMON_H /* system include */ #include #include /* Daemon define */ #define PROG_CHECK "Keepalived_healthcheckers" #define WDOG_CHECK "/tmp/.healthcheckers" /* Prototypes */ extern int start_check_child(void); #endif keepalived-1.2.13/keepalived/include/snmp.h0000664000175000017500000000443312211121152020377 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: snmp.c include file. * * Authors: Vincent Bernat * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _SNMP_H #define _SNMP_H #define USING_AGENTX_SUBAGENT_MODULE #include #include #include #include #if HAVE_NET_SNMP_AGENT_UTIL_FUNCS_H #include #else /* The above header may be buggy. We just need those two functions. */ int header_simple_table(struct variable *, oid *, size_t *, int, size_t *, WriteMethod ** write_method, int); int header_generic(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); #endif #undef FREE #include "list.h" #include "utils.h" #define KEEPALIVED_OID 1, 3, 6, 1, 4, 1, 9586, 100, 5 #define SNMPTRAP_OID 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 #define GLOBAL_OID {KEEPALIVED_OID, 1} /* For net-snmp */ extern int register_sysORTable(oid *, size_t, const char *); extern int unregister_sysORTable(oid *, size_t); extern unsigned long snmp_scope(int scope); extern void* snmp_header_list_table(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method, list dlist); extern void snmp_agent_init(oid *myoid, int len, char *name, struct variable *variables, int varsize, int varlen); extern void snmp_agent_close(oid *myoid, int len, char *name); #endif keepalived-1.2.13/keepalived/include/vrrp_if.h0000644000175000017500000001177512256127641021120 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vrrp_if.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_IF_H #define _VRRP_IF_H /* global includes */ #include /* needed to get correct values for SIOC* */ #include /* local includes */ #include "scheduler.h" #include "list.h" /* types definition */ #ifndef SIOCETHTOOL /* should not happen, otherwise we have a broken toolchain */ #warning "SIOCETHTOOL not defined. Defaulting to 0x8946, which is probably wrong !" #define SIOCETHTOOL 0x8946 #endif #ifndef SIOCGMIIPHY /* should not happen, otherwise we have a broken toolchain */ #warning "SIOCGMIIPHY not defined. Defaulting to SIOCDEVPRIVATE, which is probably wrong !" #define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Get the PHY in use. */ #define SIOCGMIIREG (SIOCGMIIPHY+1) /* Read a PHY register. */ #endif /* ethtool.h cannot be included because old versions use kernel-only types * which cannot be included from user-land. We don't need much anyway. */ #ifndef ETHTOOL_GLINK #define ETHTOOL_GLINK 0x0000000a /* for passing single values */ struct ethtool_value { uint32_t cmd; uint32_t data; }; #endif #define LINK_UP 1 #define LINK_DOWN 0 #define IF_NAMESIZ 20 /* Max interface lenght size */ #define IF_HWADDR_MAX 20 /* Max MAC address length size */ #define ARPHRD_ETHER 1 #define ARPHRD_LOOPBACK 772 #define POLLING_DELAY TIMER_HZ /* Interface Linkbeat code selection */ #define LB_IOCTL 0x1 #define LB_MII 0x2 #define LB_ETHTOOL 0x4 /* Default values */ #define IF_DEFAULT_BUFSIZE (65*1024) /* Interface structure definition */ typedef struct _interface { char ifname[IF_NAMESIZ + 1]; /* Interface name */ unsigned int ifindex; /* Interface index */ struct in_addr sin_addr; /* IPv4 primary IPv4 address */ struct in6_addr sin6_addr; /* IPv6 link address */ unsigned long flags; /* flags */ unsigned int mtu; /* MTU for this interface_t */ unsigned short hw_type; /* Type of hardware address */ u_char hw_addr[IF_HWADDR_MAX]; /* MAC address */ int hw_addr_len; /* MAC addresss length */ int lb_type; /* Interface regs selection */ int linkbeat; /* LinkBeat from MII BMSR req */ int vmac; /* Set if interface is a VMAC interface */ unsigned int base_ifindex; /* Base interface index (if interface is a VMAC interface) */ } interface_t; /* Tracked interface structure definition */ typedef struct _tracked_if { int weight; /* tracking weight when non-zero */ interface_t *ifp; /* interface backpointer, cannot be NULL */ } tracked_if_t; /* Macros */ #define IF_NAME(X) ((X)->ifname) #define IF_INDEX(X) ((X)->ifindex) #define IF_BASE_INDEX(X) ((X)->base_ifindex) #define IF_ADDR(X) ((X)->sin_addr.s_addr) #define IF_MTU(X) ((X)->mtu) #define IF_HWADDR(X) ((X)->hw_addr) #define IF_MII_SUPPORTED(X) ((X)->lb_type & LB_MII) #define IF_ETHTOOL_SUPPORTED(X) ((X)->lb_type & LB_ETHTOOL) #define IF_LINKBEAT(X) ((X)->linkbeat) #define IF_ISUP(X) (((X)->flags & IFF_UP) && \ ((X)->flags & IFF_RUNNING) && \ if_linkbeat(X)) /* prototypes */ extern interface_t *if_get_by_ifindex(const int); extern interface_t *if_get_by_vmac_base_ifindex(const int); extern interface_t *if_get_by_ifname(const char *); extern int if_linkbeat(const interface_t *); extern int if_mii_probe(const char *); extern int if_ethtool_probe(const char *); extern void if_add_queue(interface_t *); extern int if_monitor_thread(thread_t *); extern void init_interface_queue(void); extern void init_interface_linkbeat(void); extern void free_interface_queue(void); extern void dump_if(void *); extern int if_join_vrrp_group(sa_family_t, int *, interface_t *, int); extern int if_leave_vrrp_group(sa_family_t, int, interface_t *); extern int if_setsockopt_bindtodevice(int *, interface_t *); extern int if_setsockopt_hdrincl(int *); extern int if_setsockopt_mcast_loop(sa_family_t, int *); extern int if_setsockopt_mcast_hops(sa_family_t, int *); extern int if_setsockopt_mcast_if(sa_family_t, int *, interface_t *); extern int if_setsockopt_priority(int *); extern int if_setsockopt_sndbuf(int *, int); extern int if_setsockopt_rcvbuf(int *, int); #endif keepalived-1.2.13/keepalived/include/layer4.h0000644000175000017500000000332712334072037020636 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: layer4.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _LAYER4_H #define _LAYER4_H /* system includes */ #include #include #include #include #include #include #include /* local includes */ #include "scheduler.h" #include "check_api.h" enum connect_result { connect_error, connect_in_progress, connect_timeout, connect_success }; /* Prototypes defs */ extern enum connect_result tcp_bind_connect(int, conn_opts_t *); extern enum connect_result tcp_connect(int, struct sockaddr_storage *); extern enum connect_result tcp_socket_state(int, thread_t *, int (*func) (thread_t *)); extern int tcp_connection_state(int, enum connect_result , thread_t *, int (*func) (thread_t *) , long); #endif keepalived-1.2.13/keepalived/include/vrrp_daemon.h0000664000175000017500000000240412211121152021732 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vrrp_daemon.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_DAEMON_H #define _VRRP_DAEMON_H /* system include */ #include #include /* Daemon define */ #define PROG_VRRP "Keepalived_vrrp" #define WDOG_VRRP "/tmp/.vrrp" /* Prototypes */ extern int start_vrrp_child(void); #endif keepalived-1.2.13/keepalived/include/check_snmp.h0000664000175000017500000001073312211376366021557 0ustar acassenacassen/* * Soft: Vrrpd is an implementation of VRRPv2 as specified in rfc2338. * VRRP is a protocol which elect a master server on a LAN. If the * master fails, a backup server takes over. * The original implementation has been made by jerome etienne. * * Part: check_snmp.c program include file. * * Author: Vincent Bernat * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _CHECK_SNMP_H #define _CHECK_SNMP_H #include "snmp.h" /* CHECK SNMP defines */ #define CHECK_OID KEEPALIVED_OID, 3 #define CHECK_SNMP_VSGROUPNAME 1 #define CHECK_SNMP_VSGROUPMEMBERTYPE 3 #define CHECK_SNMP_VSGROUPMEMBERFWMARK 4 #define CHECK_SNMP_VSGROUPMEMBERADDRTYPE 5 #define CHECK_SNMP_VSGROUPMEMBERADDRESS 6 #define CHECK_SNMP_VSGROUPMEMBERADDR1 7 #define CHECK_SNMP_VSGROUPMEMBERADDR2 8 #define CHECK_SNMP_VSGROUPMEMBERPORT 9 #define CHECK_SNMP_VSTYPE 10 #define CHECK_SNMP_VSNAMEGROUP 14 #define CHECK_SNMP_VSFWMARK 11 #define CHECK_SNMP_VSADDRTYPE 12 #define CHECK_SNMP_VSADDRESS 13 #define CHECK_SNMP_VSPORT 16 #define CHECK_SNMP_VSPROTOCOL 17 #define CHECK_SNMP_VSLOADBALANCINGALGO 18 #define CHECK_SNMP_VSLOADBALANCINGKIND 19 #define CHECK_SNMP_VSSTATUS 20 #define CHECK_SNMP_VSVIRTUALHOST 21 #define CHECK_SNMP_VSPERSIST 22 #define CHECK_SNMP_VSPERSISTTIMEOUT 23 #define CHECK_SNMP_VSPERSISTGRANULARITY 24 #define CHECK_SNMP_VSDELAYLOOP 25 #define CHECK_SNMP_VSHASUSPEND 26 #define CHECK_SNMP_VSALPHA 27 #define CHECK_SNMP_VSOMEGA 28 #define CHECK_SNMP_VSQUORUM 29 #define CHECK_SNMP_VSQUORUMSTATUS 30 #define CHECK_SNMP_VSQUORUMUP 31 #define CHECK_SNMP_VSQUORUMDOWN 32 #define CHECK_SNMP_VSHYSTERESIS 33 #define CHECK_SNMP_VSREALTOTAL 34 #define CHECK_SNMP_VSREALUP 35 #define CHECK_SNMP_VSSTATSCONNS 61 #define CHECK_SNMP_VSSTATSINPKTS 62 #define CHECK_SNMP_VSSTATSOUTPKTS 63 #define CHECK_SNMP_VSSTATSINBYTES 64 #define CHECK_SNMP_VSSTATSOUTBYTES 65 #define CHECK_SNMP_VSRATECPS 66 #define CHECK_SNMP_VSRATEINPPS 67 #define CHECK_SNMP_VSRATEOUTPPS 68 #define CHECK_SNMP_VSRATEINBPS 69 #define CHECK_SNMP_VSRATEOUTBPS 70 #define CHECK_SNMP_RSTYPE 36 #define CHECK_SNMP_RSADDRTYPE 37 #define CHECK_SNMP_RSADDRESS 38 #define CHECK_SNMP_RSPORT 39 #define CHECK_SNMP_RSSTATUS 40 #define CHECK_SNMP_RSWEIGHT 41 #define CHECK_SNMP_RSUPPERCONNECTIONLIMIT 42 #define CHECK_SNMP_RSLOWERCONNECTIONLIMIT 43 #define CHECK_SNMP_RSACTIONWHENDOWN 44 #define CHECK_SNMP_RSNOTIFYUP 45 #define CHECK_SNMP_RSNOTIFYDOWN 46 #define CHECK_SNMP_RSFAILEDCHECKS 47 #define CHECK_SNMP_RSSTATSCONNS 48 #define CHECK_SNMP_RSSTATSACTIVECONNS 49 #define CHECK_SNMP_RSSTATSINACTIVECONNS 50 #define CHECK_SNMP_RSSTATSPERSISTENTCONNS 51 #define CHECK_SNMP_RSSTATSINPKTS 52 #define CHECK_SNMP_RSSTATSOUTPKTS 53 #define CHECK_SNMP_RSSTATSINBYTES 54 #define CHECK_SNMP_RSSTATSOUTBYTES 55 #define CHECK_SNMP_RSRATECPS 56 #define CHECK_SNMP_RSRATEINPPS 57 #define CHECK_SNMP_RSRATEOUTPPS 58 #define CHECK_SNMP_RSRATEINBPS 59 #define CHECK_SNMP_RSRATEOUTBPS 60 #define CHECK_SNMP_VSOPS 71 #define STATE_VSGM_FWMARK 1 #define STATE_VSGM_ADDRESS 2 #define STATE_VSGM_RANGE 3 #define STATE_VSGM_END 4 #define STATE_RS_SORRY 1 #define STATE_RS_REGULAR_FIRST 2 #define STATE_RS_REGULAR_NEXT 3 #define STATE_RS_END 4 /* Macro */ #define RETURN_IP46ADDRESS(entity) \ do { \ if (entity->addr.ss_family == AF_INET6) { \ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&entity->addr; \ *var_len = 16; \ return (u_char *)&addr6->sin6_addr; \ } else { \ struct sockaddr_in *addr4 = (struct sockaddr_in *)&entity->addr; \ *var_len = 4; \ return (u_char *)&addr4->sin_addr; \ } \ } while(0) /* Prototypes */ extern void check_snmp_agent_init(void); extern void check_snmp_agent_close(void); extern void check_snmp_rs_trap(real_server_t *, virtual_server_t *); extern void check_snmp_quorum_trap(virtual_server_t *); #endif keepalived-1.2.13/keepalived/include/pidfile.h0000664000175000017500000000306712211121152021040 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: pidfile.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _PIDFILE_H #define _PIDFILE_H /* system include */ #include #include #include #include #include /* lock pidfile */ #define KEEPALIVED_PID_FILE "/var/run/keepalived.pid" #define KEEPALIVED_VRRP_PID_FILE "/var/run/keepalived_vrrp.pid" #define KEEPALIVED_CHECKERS_PID_FILE "/var/run/keepalived_checkers.pid" #define VRRP_PID_FILE "/var/run/vrrp.pid" #define CHECKERS_PID_FILE "/var/run/checkers.pid" /* Prototypes */ extern int pidfile_write(char *, int); extern void pidfile_rm(char *); extern int keepalived_running(int); #endif keepalived-1.2.13/keepalived/include/check_parser.h0000664000175000017500000000221212211121152022044 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: check_parser.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _CHECK_PARSER_H #define _CHECK_PARSER_H /* local include */ #include "vector.h" /* Prototypes */ extern vector_t *check_init_keywords(void); #endif keepalived-1.2.13/keepalived/include/vrrp_snmp.h0000664000175000017500000001040712211121152021446 0ustar acassenacassen/* * Soft: Vrrpd is an implementation of VRRPv2 as specified in rfc2338. * VRRP is a protocol which elect a master server on a LAN. If the * master fails, a backup server takes over. * The original implementation has been made by jerome etienne. * * Part: vrrp_snmp.c program include file. * * Author: Vincent Bernat * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_SNMP_H #define _VRRP_SNMP_H #include "snmp.h" /* VRRP SNMP defines */ #define VRRP_OID KEEPALIVED_OID, 2 #define VRRP_SNMP_SCRIPT_NAME 3 #define VRRP_SNMP_SCRIPT_COMMAND 4 #define VRRP_SNMP_SCRIPT_INTERVAL 5 #define VRRP_SNMP_SCRIPT_WEIGHT 6 #define VRRP_SNMP_SCRIPT_RESULT 7 #define VRRP_SNMP_SCRIPT_RISE 8 #define VRRP_SNMP_SCRIPT_FALL 9 #define VRRP_SNMP_ADDRESS_ADDRESSTYPE 9 #define VRRP_SNMP_ADDRESS_VALUE 10 #define VRRP_SNMP_ADDRESS_BROADCAST 11 #define VRRP_SNMP_ADDRESS_MASK 12 #define VRRP_SNMP_ADDRESS_SCOPE 13 #define VRRP_SNMP_ADDRESS_IFINDEX 14 #define VRRP_SNMP_ADDRESS_IFNAME 15 #define VRRP_SNMP_ADDRESS_IFALIAS 16 #define VRRP_SNMP_ADDRESS_ISSET 17 #define VRRP_SNMP_ADDRESS_ISADVERTISED 18 #define VRRP_SNMP_ROUTE_ADDRESSTYPE 19 #define VRRP_SNMP_ROUTE_DESTINATION 20 #define VRRP_SNMP_ROUTE_DESTINATIONMASK 21 #define VRRP_SNMP_ROUTE_GATEWAY 22 #define VRRP_SNMP_ROUTE_SECONDARYGATEWAY 23 #define VRRP_SNMP_ROUTE_SOURCE 24 #define VRRP_SNMP_ROUTE_METRIC 25 #define VRRP_SNMP_ROUTE_SCOPE 26 #define VRRP_SNMP_ROUTE_TYPE 27 #define VRRP_SNMP_ROUTE_IFINDEX 28 #define VRRP_SNMP_ROUTE_IFNAME 29 #define VRRP_SNMP_ROUTE_ROUTINGTABLE 30 #define VRRP_SNMP_ROUTE_ISSET 31 #define VRRP_SNMP_SYNCGROUP_NAME 33 #define VRRP_SNMP_SYNCGROUP_STATE 34 #define VRRP_SNMP_SYNCGROUP_SMTPALERT 35 #define VRRP_SNMP_SYNCGROUP_NOTIFYEXEC 36 #define VRRP_SNMP_SYNCGROUP_SCRIPTMASTER 37 #define VRRP_SNMP_SYNCGROUP_SCRIPTBACKUP 38 #define VRRP_SNMP_SYNCGROUP_SCRIPTFAULT 39 #define VRRP_SNMP_SYNCGROUP_SCRIPT 40 #define VRRP_SNMP_SYNCGROUPMEMBER_INSTANCE 42 #define VRRP_SNMP_SYNCGROUPMEMBER_NAME 43 #define VRRP_SNMP_INSTANCE_NAME 45 #define VRRP_SNMP_INSTANCE_VIRTUALROUTERID 46 #define VRRP_SNMP_INSTANCE_STATE 47 #define VRRP_SNMP_INSTANCE_INITIALSTATE 48 #define VRRP_SNMP_INSTANCE_WANTEDSTATE 49 #define VRRP_SNMP_INSTANCE_BASEPRIORITY 50 #define VRRP_SNMP_INSTANCE_EFFECTIVEPRIORITY 51 #define VRRP_SNMP_INSTANCE_VIPSENABLED 52 #define VRRP_SNMP_INSTANCE_PRIMARYINTERFACE 53 #define VRRP_SNMP_INSTANCE_TRACKPRIMARYIF 54 #define VRRP_SNMP_INSTANCE_ADVERTISEMENTSINT 55 #define VRRP_SNMP_INSTANCE_PREEMPT 56 #define VRRP_SNMP_INSTANCE_PREEMPTDELAY 57 #define VRRP_SNMP_INSTANCE_AUTHTYPE 58 #define VRRP_SNMP_INSTANCE_USELVSSYNCDAEMON 59 #define VRRP_SNMP_INSTANCE_LVSSYNCINTERFACE 60 #define VRRP_SNMP_INSTANCE_SYNCGROUP 61 #define VRRP_SNMP_INSTANCE_GARPDELAY 62 #define VRRP_SNMP_INSTANCE_SMTPALERT 63 #define VRRP_SNMP_INSTANCE_NOTIFYEXEC 64 #define VRRP_SNMP_INSTANCE_SCRIPTMASTER 65 #define VRRP_SNMP_INSTANCE_SCRIPTBACKUP 66 #define VRRP_SNMP_INSTANCE_SCRIPTFAULT 67 #define VRRP_SNMP_INSTANCE_SCRIPTSTOP 68 #define VRRP_SNMP_INSTANCE_SCRIPT 69 #define VRRP_SNMP_TRACKEDINTERFACE_NAME 70 #define VRRP_SNMP_TRACKEDINTERFACE_WEIGHT 71 #define VRRP_SNMP_TRACKEDSCRIPT_NAME 73 #define VRRP_SNMP_TRACKEDSCRIPT_WEIGHT 74 #define HEADER_STATE_STATIC_ADDRESS 1 #define HEADER_STATE_VIRTUAL_ADDRESS 2 #define HEADER_STATE_EXCLUDED_VIRTUAL_ADDRESS 3 #define HEADER_STATE_STATIC_ROUTE 4 #define HEADER_STATE_VIRTUAL_ROUTE 5 #define HEADER_STATE_END 10 /* Prototypes */ extern void vrrp_snmp_agent_init(void); extern void vrrp_snmp_agent_close(void); extern void vrrp_snmp_instance_trap(vrrp_t *); extern void vrrp_snmp_group_trap(vrrp_sgroup_t *); #endif keepalived-1.2.13/keepalived/include/vrrp_ndisc.h0000664000175000017500000000437312211121152021576 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vrrp_ndisc.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_NDISC_H #define _VRRP_NDISC_H /* system includes */ #include /* local definitions */ #define ETHERNET_HW_LEN 6 #define NEXTHDR_ICMP 58 #define NDISC_HOPLIMIT 255 /* * ICMPv6 codes for Neighbour Discovery messages */ #define NDISC_ROUTER_SOLICITATION 133 #define NDISC_ROUTER_ADVERTISEMENT 134 #define NDISC_NEIGHBOUR_SOLICITATION 135 #define NDISC_NEIGHBOUR_ADVERTISEMENT 136 #define NDISC_REDIRECT 137 /* * Neighbour Discovery option codes */ #define ND_OPT_TARGET_LL_ADDR 2 /* * IPv6 Header */ struct ip6hdr { #if defined(__LITTLE_ENDIAN_BITFIELD) __u8 priority:4, version:4; #elif defined(__BIG_ENDIAN_BITFIELD) __u8 version:4, priority:4; #else #error "Please fix " #endif __u8 flow_lbl[3]; __be16 payload_len; __u8 nexthdr; __u8 hop_limit; struct in6_addr saddr; struct in6_addr daddr; }; /* * NDISC Neighbour Advertisement related */ struct ndhdr { struct icmp6hdr icmph; struct in6_addr target; __u8 opt[0]; }; struct nd_opt_hdr { __u8 nd_opt_type; __u8 nd_opt_len; } __attribute__((__packed__)); /* prototypes */ extern void ndisc_init(void); extern void ndisc_close(void); extern int ndisc_send_unsolicited_na(ip_address_t *); #endif keepalived-1.2.13/keepalived/include/vrrp_index.h0000664000175000017500000000273712211121152021607 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vrrp_index.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_INDEX_H #define _VRRP_INDEX_H /* global includes */ #include #include #include #include #include /* local includes */ #include "vrrp.h" /* Macro definition */ /* prototypes */ extern void alloc_vrrp_bucket(vrrp_t *); extern void alloc_vrrp_fd_bucket(vrrp_t *); extern void remove_vrrp_fd_bucket(vrrp_t *); extern void set_vrrp_fd_bucket(int, vrrp_t *); extern vrrp_t *vrrp_index_lookup(const int, const int); #endif keepalived-1.2.13/keepalived/include/check_tcp.h0000644000175000017500000000242212334072037021354 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: check_tcp.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _CHECK_TCP_H #define _CHECK_TCP_H /* system includes */ #include #include #include /* local includes */ #include "scheduler.h" /* macro utility */ #define FMT_TCP_RS(C) FMT_CHK(C) /* Prototypes defs */ extern void install_tcp_check_keyword(void); #endif keepalived-1.2.13/keepalived/include/vrrp_arp.h0000644000175000017500000000416112256127641021273 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vrrp_arp.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_ARP_H #define _VRRP_ARP_H /* system includes */ #include #include /* local includes */ #include "vrrp_ipaddress.h" /* local definitions */ #define ETHERNET_HW_LEN 6 #define IPPROTO_ADDR_LEN 4 /* types definition */ typedef struct _arphdr { unsigned short int ar_hrd; /* Format of hardware address. */ unsigned short int ar_pro; /* Format of protocol address. */ unsigned char ar_hln; /* Length of hardware address. */ unsigned char ar_pln; /* Length of protocol address. */ unsigned short int ar_op; /* ARP opcode (command). */ /* Ethernet looks like this : This bit is variable sized however... */ unsigned char __ar_sha[ETH_ALEN]; /* Sender hardware address. */ unsigned char __ar_sip[4]; /* Sender IP address. */ unsigned char __ar_tha[ETH_ALEN]; /* Target hardware address. */ unsigned char __ar_tip[4]; /* Target IP address. */ } arphdr_t; /* Global vars exported */ extern char *garp_buffer; extern int garp_fd; /* prototypes */ extern void gratuitous_arp_init(void); extern void gratuitous_arp_close(void); extern int send_gratuitous_arp(ip_address_t *); #endif keepalived-1.2.13/keepalived/include/ipwrapper.h0000664000175000017500000000401112212660136021436 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: ipwrapper.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _IPWRAPPER_H #define _IPWRAPPER_H /* system includes */ #include /* locale includes */ #include "check_data.h" #include "smtp.h" /* NAT netmask */ #define HOST_NETMASK 0xffffffff /* firewall rules framework command */ #define IP_FW_CMD_ADD 0x0001 #define IP_FW_CMD_DEL 0x0002 /* UP & DOWN value */ #define UP 1 #define DOWN 0 /* LVS command set by kernel */ #define LVS_CMD_ADD IP_VS_SO_SET_ADD #define LVS_CMD_DEL IP_VS_SO_SET_DEL #define LVS_CMD_ADD_DEST IP_VS_SO_SET_ADDDEST #define LVS_CMD_DEL_DEST IP_VS_SO_SET_DELDEST #define LVS_CMD_EDIT_DEST IP_VS_SO_SET_EDITDEST /* prototypes */ extern void perform_svr_state(int, virtual_server_t *, real_server_t *); extern void update_svr_wgt(int, virtual_server_t *, real_server_t *); extern int svr_checker_up(checker_id_t, real_server_t *); extern void update_svr_checker_state(int, checker_id_t, virtual_server_t *, real_server_t *); extern int init_services(void); extern int clear_services(void); extern int clear_diff_services(void); extern int copy_srv_states(void); #endif keepalived-1.2.13/keepalived/include/vrrp_notify.h0000664000175000017500000000237512211121152022006 0ustar acassenacassen/* * Soft: Vrrpd is an implementation of VRRPv2 as specified in rfc2338. * VRRP is a protocol which elect a master server on a LAN. If the * master fails, a backup server takes over. * The original implementation has been made by jerome etienne. * * Part: vrrp_notify.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_NOTIFY_H #define _VRRP_NOTIFY_H /* local include */ #include "vrrp.h" extern int notify_instance_exec(vrrp_t *, int); extern int notify_group_exec(vrrp_sgroup_t *, int); #endif keepalived-1.2.13/keepalived/include/vrrp_sync.h0000664000175000017500000000350412211121152021445 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vrrp_sync.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_SYNC_H #define _VRRP_SYNC_H /* system include */ #include #include #include #include #include /* local include */ #include "vrrp.h" /* TSM size */ #define VRRP_MAX_TSM_STATE 3 /* MACRO definition */ #define GROUP_STATE(G) ((G)->state) #define GROUP_NAME(G) ((G)->gname) /* extern prototypes */ extern void vrrp_init_instance_sands(vrrp_t *); extern void vrrp_sync_smtp_notifier(vrrp_sgroup_t *); extern void vrrp_sync_set_group(vrrp_sgroup_t *); extern int vrrp_sync_group_up(vrrp_sgroup_t *); extern int vrrp_sync_leave_fault(vrrp_t *); extern int vrrp_sync_goto_master(vrrp_t *); extern void vrrp_sync_backup(vrrp_t *); extern void vrrp_sync_master(vrrp_t *); extern void vrrp_sync_master_election(vrrp_t *); extern void vrrp_sync_fault(vrrp_t *); #endif keepalived-1.2.13/keepalived/include/check_api.h0000644000175000017500000000673312334072232021345 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Checkers arguments structures definitions. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _CHECK_API_H #define _CHECK_API_H /* local includes */ #include "check_data.h" #include "scheduler.h" /* connection options structure definition */ typedef struct _conn_opts { struct sockaddr_storage dst; struct sockaddr_storage bindto; unsigned int connection_to; /* connection time-out */ #ifdef _WITH_SO_MARK_ unsigned int fwmark; /* to mark packets going out of the socket using SO_MARK */ #endif } conn_opts_t; /* Checkers structure definition */ typedef struct _checker { void (*free_func) (void *); void (*dump_func) (void *); int (*launch) (struct _thread *); int (*plugin_launch) (void *); virtual_server_t *vs; /* pointer to the checker thread virtualserver */ real_server_t *rs; /* pointer to the checker thread realserver */ void *data; checker_id_t id; /* Checker identifier */ int enabled;/* Activation flag */ conn_opts_t *co; /* connection options */ long warmup; /* max random timeout to start checker */ } checker_t; /* Checkers queue */ extern list checkers_queue; /* utility macro */ #define CHECKER_ARG(X) ((X)->data) #define CHECKER_CO(X) (((checker_t *)X)->co) #define CHECKER_DATA(X) (((checker_t *)X)->data) #define CHECKER_GET_CURRENT() (LIST_TAIL_DATA(checkers_queue)) #define CHECKER_GET() (CHECKER_DATA(CHECKER_GET_CURRENT())) #define CHECKER_GET_CO() (((checker_t *)CHECKER_GET_CURRENT())->co) #define CHECKER_VALUE_INT(X) (atoi(vector_slot(X,1))) #define CHECKER_VALUE_STRING(X) (set_value(X)) #define CHECKER_VHOST(C) (VHOST((C)->vs)) #define CHECKER_ENABLED(C) ((C)->enabled) #define CHECKER_ENABLE(C) ((C)->enabled = 1) #define CHECKER_DISABLE(C) ((C)->enabled = 0) #define CHECKER_HA_SUSPEND(C) ((C)->vs->ha_suspend) #define CHECKER_NEW_CO() ((conn_opts_t *) MALLOC(sizeof (conn_opts_t))) #define FMT_CHK(C) FMT_RS((C)->rs) /* Prototypes definition */ extern void init_checkers_queue(void); extern void dump_conn_opts (conn_opts_t *); extern void queue_checker(void (*free_func) (void *), void (*dump_func) (void *) , int (*launch) (thread_t *) , void * , conn_opts_t *); extern void dump_checkers_queue(void); extern void free_checkers_queue(void); extern void register_checkers_thread(void); extern void install_checkers_keyword(void); extern void install_connect_keywords(void); extern void warmup_handler(vector_t *); extern void update_checker_activity(sa_family_t, void *, int); extern void checker_set_dst(struct sockaddr_storage *); extern void checker_set_dst_port(struct sockaddr_storage *, uint16_t); #endif keepalived-1.2.13/keepalived/include/vrrp_scheduler.h0000664000175000017500000000375712211121152022461 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vrrp_scheduler.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_SCHEDULER_H #define _VRRP_SCHEDULER_H /* system include */ #include #include #include #include #include /* local includes */ #include "scheduler.h" #include "list.h" #include "vrrp_data.h" /* VRRP FSM Macro */ #define VRRP_FSM_READ_TO(V) \ do { \ if ((*(VRRP_FSM[(V)->state].read_to))) \ (*(VRRP_FSM[(V)->state].read_to)) (V); \ } while (0) #define VRRP_FSM_READ(V, B, L) \ do { \ if ((*(VRRP_FSM[(V)->state].read))) \ (*(VRRP_FSM[(V)->state].read)) (V, B, L); \ } while (0) /* VRRP TSM Macro */ #define VRRP_TSM_HANDLE(S,V) \ do { \ if ((V)->sync && \ S != VRRP_STATE_GOTO_MASTER) \ if ((*(VRRP_TSM[S][(V)->state].handler))) \ (*(VRRP_TSM[S][(V)->state].handler)) (V); \ } while (0) /* extern prototypes */ extern void vrrp_dispatcher_release(vrrp_data_t *); extern int vrrp_dispatcher_init(thread_t *); extern int vrrp_read_dispatcher_thread(thread_t *); #endif keepalived-1.2.13/keepalived/include/ipvswrapper.h0000664000175000017500000000614212211121152022003 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: ipvswrapper.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _IPVSWRAPPER_H #define _IPVSWRAPPER_H /* system includes */ #include #include #include #include #include #include #include #include #include #include #include #ifdef _WITH_LVS_ #ifdef _KRNL_2_4_ #include "../libipvs-2.4/libipvs.h" #include #elif _KRNL_2_6_ #include "../libipvs-2.6/ip_vs.h" #include "../libipvs-2.6/libipvs.h" #endif // #include #endif #ifndef IP_VS_TEMPLATE_TIMEOUT #define IP_VS_TEMPLATE_TIMEOUT IPVS_SVC_PERSISTENT_TIMEOUT #endif /* locale includes */ #include "scheduler.h" #include "check_data.h" #define IPVS_ERROR 0 #define IPVS_SUCCESS 1 #define IPVS_CMD_DELAY 3 #ifdef _HAVE_IPVS_SYNCD_ #define IPVS_STARTDAEMON IP_VS_SO_SET_STARTDAEMON #define IPVS_STOPDAEMON IP_VS_SO_SET_STOPDAEMON #define IPVS_MASTER IP_VS_STATE_MASTER #define IPVS_BACKUP IP_VS_STATE_BACKUP #else #define IPVS_STARTDAEMON 1 #define IPVS_STOPDAEMON 2 #define IPVS_MASTER 3 #define IPVS_BACKUP 4 #endif /* Macro */ #define IPVS_ALIVE(X,Y,Z) (((X) == IP_VS_SO_SET_ADD && !(Y)->alive) || \ ((X) == IP_VS_SO_SET_DEL && (Y)->alive) || \ ((X) == IP_VS_SO_SET_ADDDEST && !(Z)->alive) || \ ((X) == IP_VS_SO_SET_DELDEST && (Z)->alive) || \ (X) == IP_VS_SO_SET_EDITDEST \ ) #define IPVS_SET_ALIVE(C,V) \ do { \ if ((C) == IP_VS_SO_SET_ADD) \ SET_ALIVE((V)); \ if ((C) == IP_VS_SO_SET_DEL) \ UNSET_ALIVE((V)); \ } while (0) /* prototypes */ extern int ipvs_start(void); extern void ipvs_stop(void); extern virtual_server_group_t *ipvs_get_group_by_name(char *, list); extern int ipvs_group_remove_entry(virtual_server_t *, virtual_server_group_entry_t *); extern int ipvs_cmd(int, list, virtual_server_t *, real_server_t *); extern int ipvs_syncd_cmd(int, char *, int, int); extern void ipvs_syncd_master(char *, int); extern void ipvs_syncd_backup(char *, int); #ifdef _KRNL_2_6_ /* Refresh statistics at most every 5 seconds */ #define STATS_REFRESH 5 extern void ipvs_update_stats(virtual_server_t * vs); #endif #endif keepalived-1.2.13/keepalived/include/global_parser.h0000664000175000017500000000216312211121152022234 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vrrp_parser.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _GLOBAL_PARSER_H #define _GLOBAL_PARSER_H /* local include */ /* Prototypes */ extern void global_init_keywords(void); #endif keepalived-1.2.13/keepalived/include/main.h0000664000175000017500000000341312217776071020371 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Main program include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _MAIN_H #define _MAIN_H /* global includes */ #include #include #include /* local includes */ #include "daemon.h" #include "memory.h" #include "utils.h" #include "pidfile.h" #include "scheduler.h" #include "parser.h" #include "vrrp_daemon.h" #include "check_daemon.h" #include "global_data.h" /* Global vars exported */ extern char *conf_file; /* Configuration file */ extern int log_facility; /* Optional logging facilities */ extern pid_t vrrp_child; /* VRRP child process ID */ extern pid_t checkers_child; /* Healthcheckers child process ID */ extern int daemon_mode; /* VRRP/CHECK subsystem selection */ extern int linkwatch; /* Use linkwatch kernel netlink reflection */ #ifdef _WITH_SNMP_ extern int snmp; /* Enable SNMP support */ #endif #endif keepalived-1.2.13/keepalived/include/check_data.h0000644000175000017500000001763112334072037021507 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Healthcheckers dynamic data structure definition. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _CHECK_DATA_H #define _CHECK_DATA_H /* system includes */ #include #include #include #include #include #include #ifdef _WITH_LVS_ #ifdef _KRNL_2_4_ #include #elif _KRNL_2_6_ #include "../libipvs-2.6/ip_vs.h" #endif #define SCHED_MAX_LENGTH IP_VS_SCHEDNAME_MAXLEN #else #define SCHED_MAX_LENGTH 1 #endif /* local includes */ #include "list.h" #include "vector.h" #include "timer.h" /* Typedefs */ typedef unsigned int checker_id_t; /* Daemon dynamic data structure definition */ #define MAX_TIMEOUT_LENGTH 5 #define KEEPALIVED_DEFAULT_DELAY (60 * TIMER_HZ) /* SSL specific data */ typedef struct _ssl_data { int enable; int strong_check; SSL_CTX *ctx; SSL_METHOD *meth; char *password; char *cafile; char *certfile; char *keyfile; } ssl_data_t; /* Real Server definition */ typedef struct _real_server { struct sockaddr_storage addr; int weight; int iweight; /* Initial weight */ #ifdef _KRNL_2_6_ uint32_t u_threshold; /* Upper connection limit. */ uint32_t l_threshold; /* Lower connection limit. */ #endif int inhibit; /* Set weight to 0 instead of removing * the service from IPVS topology. */ char *notify_up; /* Script to launch when RS is added to LVS */ char *notify_down; /* Script to launch when RS is removed from LVS */ int alive; list failed_checkers;/* List of failed checkers */ int set; /* in the IPVS table */ int reloaded; /* active state was copied from old config while reloading */ #if defined(_WITH_SNMP_) && defined(_KRNL_2_6_) && defined(_WITH_LVS_) /* Statistics */ uint32_t activeconns; /* active connections */ uint32_t inactconns; /* inactive connections */ uint32_t persistconns; /* persistent connections */ struct ip_vs_stats_user stats; #endif } real_server_t; /* Virtual Server group definition */ typedef struct _virtual_server_group_entry { struct sockaddr_storage addr; uint8_t range; uint32_t vfwmark; int alive; } virtual_server_group_entry_t; typedef struct _virtual_server_group { char *gname; list addr_ip; list range; list vfwmark; } virtual_server_group_t; /* Virtual Server definition */ typedef struct _virtual_server { char *vsgname; struct sockaddr_storage addr; real_server_t *s_svr; uint32_t vfwmark; uint16_t service_type; long delay_loop; int ha_suspend; int ops; char sched[SCHED_MAX_LENGTH]; char timeout_persistence[MAX_TIMEOUT_LENGTH]; unsigned loadbalancing_kind; uint32_t nat_mask; uint32_t granularity_persistence; char *virtualhost; list rs; int alive; unsigned alpha; /* Alpha mode enabled. */ unsigned omega; /* Omega mode enabled. */ char *quorum_up; /* A hook to call when the VS gains quorum. */ char *quorum_down; /* A hook to call when the VS loses quorum. */ long unsigned quorum; /* Minimum live RSs to consider VS up. */ long unsigned hysteresis; /* up/down events "lag" WRT quorum. */ unsigned quorum_state; /* Reflects result of the last transition done. */ int reloaded; /* quorum_state was copied from old config while reloading */ #if defined(_WITH_SNMP_) && defined(_KRNL_2_6_) && defined(_WITH_LVS_) /* Statistics */ time_t lastupdated; struct ip_vs_stats_user stats; #endif } virtual_server_t; /* Configuration data root */ typedef struct _check_data { ssl_data_t *ssl; list vs_group; list vs; } check_data_t; /* inline stuff */ static inline int __ip6_addr_equal(const struct in6_addr *a1, const struct in6_addr *a2) { return (((a1->s6_addr32[0] ^ a2->s6_addr32[0]) | (a1->s6_addr32[1] ^ a2->s6_addr32[1]) | (a1->s6_addr32[2] ^ a2->s6_addr32[2]) | (a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0); } static inline int sockstorage_equal(const struct sockaddr_storage *s1, const struct sockaddr_storage *s2) { if (s1->ss_family != s2->ss_family) return 0; if (s1->ss_family == AF_INET6) { struct sockaddr_in6 *a1 = (struct sockaddr_in6 *) s1; struct sockaddr_in6 *a2 = (struct sockaddr_in6 *) s2; // if (IN6_ARE_ADDR_EQUAL(a1, a2) && (a1->sin6_port == a2->sin6_port)) if (__ip6_addr_equal(&a1->sin6_addr, &a2->sin6_addr) && (a1->sin6_port == a2->sin6_port)) return 1; } else if (s1->ss_family == AF_INET) { struct sockaddr_in *a1 = (struct sockaddr_in *) s1; struct sockaddr_in *a2 = (struct sockaddr_in *) s2; if ((a1->sin_addr.s_addr == a2->sin_addr.s_addr) && (a1->sin_port == a2->sin_port)) return 1; } else if (s1->ss_family == AF_UNSPEC) return 1; return 0; } static inline int inaddr_equal(sa_family_t family, void *addr1, void *addr2) { if (family == AF_INET6) { struct in6_addr *a1 = (struct in6_addr *) addr1; struct in6_addr *a2 = (struct in6_addr *) addr2; if (__ip6_addr_equal(a1, a2)) return 1; } else if (family == AF_INET) { struct in_addr *a1 = (struct in_addr *) addr1; struct in_addr *a2 = (struct in_addr *) addr2; if (a1->s_addr == a2->s_addr) return 1; } return 0; } /* macro utility */ #define ISALIVE(S) ((S)->alive) #define SET_ALIVE(S) ((S)->alive = 1) #define UNSET_ALIVE(S) ((S)->alive = 0) #define VHOST(V) ((V)->virtualhost) #define FMT_RS(R) (inet_sockaddrtopair (&(R)->addr)) #define FMT_VS(V) (format_vs((V))) #define VS_ISEQ(X,Y) (sockstorage_equal(&(X)->addr,&(Y)->addr) &&\ (X)->vfwmark == (Y)->vfwmark &&\ (X)->service_type == (Y)->service_type &&\ (X)->loadbalancing_kind == (Y)->loadbalancing_kind &&\ (X)->nat_mask == (Y)->nat_mask &&\ (X)->granularity_persistence == (Y)->granularity_persistence &&\ ( (!(X)->quorum_up && !(Y)->quorum_up) || \ ((X)->quorum_up && (Y)->quorum_up && !strcmp ((X)->quorum_up, (Y)->quorum_up)) \ ) &&\ !strcmp((X)->sched, (Y)->sched) &&\ !strcmp((X)->timeout_persistence, (Y)->timeout_persistence) &&\ (((X)->vsgname && (Y)->vsgname && \ !strcmp((X)->vsgname, (Y)->vsgname)) || \ (!(X)->vsgname && !(Y)->vsgname))) #define VSGE_ISEQ(X,Y) (sockstorage_equal(&(X)->addr,&(Y)->addr) && \ (X)->range == (Y)->range && \ (X)->vfwmark == (Y)->vfwmark) #define RS_ISEQ(X,Y) (sockstorage_equal(&(X)->addr,&(Y)->addr) && \ (X)->iweight == (Y)->iweight) /* Global vars exported */ extern check_data_t *check_data; extern check_data_t *old_check_data; /* prototypes */ extern ssl_data_t *alloc_ssl(void); extern void free_ssl(void); extern void alloc_vsg(char *); extern void alloc_vsg_entry(vector_t *); extern void alloc_vs(char *, char *); extern void alloc_rs(char *, char *); extern void alloc_ssvr(char *, char *); extern void alloc_group(char *); extern void alloc_rsgroup(char *, char *); extern void set_rsgroup(char *); extern check_data_t *alloc_check_data(void); extern void free_check_data(check_data_t *); extern void dump_check_data(check_data_t *); extern char *format_vs (virtual_server_t *); #endif keepalived-1.2.13/keepalived/include/check_ssl.h0000664000175000017500000000262712211121152021363 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: check_http.c include file. * * Authors: Alexandre Cassen, * Jan Holmberg, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _CHECK_SSL_H #define _CHECK_SSL_H /* local includes */ #include "check_http.h" /* Prototypes */ extern void install_ssl_check_keyword(void); extern int init_ssl_ctx(void); extern void clear_ssl(ssl_data_t *); extern int ssl_connect(thread_t *, int); extern int ssl_printerr(int); extern int ssl_send_request(SSL *, char *, int); extern int ssl_read_thread(thread_t *); #endif keepalived-1.2.13/keepalived/include/vrrp_ipaddress.h0000644000175000017500000000642612334106407022467 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vrrp_ipaddress.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_IPADDR_H #define _VRRP_IPADDR_H /* global includes */ #include #include #define __USE_GNU #include #include #include #include /* local includes */ #include "vrrp_if.h" #include "list.h" #include "vector.h" /* types definition */ typedef struct _ip_address { struct ifaddrmsg ifa; union { struct { struct in_addr sin_addr; struct in_addr sin_brd; } sin; struct in6_addr sin6_addr; } u; interface_t *ifp; /* Interface owning IP address */ char *label; /* Alias name, e.g. eth0:1 */ int set; /* TRUE if addr is set */ } ip_address_t; #define IPADDRESS_DEL 0 #define IPADDRESS_ADD 1 #define DFLT_INT "eth0" /* Macro definition */ #define IP_FAMILY(X) (X)->ifa.ifa_family #define IP_IS6(X) ((X)->ifa.ifa_family == AF_INET6) #define IP_SIZE(X) (IP_IS6(X) ? sizeof((X)->u.sin6_addr) : sizeof((X)->u.sin.sin_addr)) #define IP4_ISEQ(X,Y) ((X)->u.sin.sin_addr.s_addr == (Y)->u.sin.sin_addr.s_addr && \ (X)->ifa.ifa_prefixlen == (Y)->ifa.ifa_prefixlen && \ (X)->ifa.ifa_index == (Y)->ifa.ifa_index && \ (X)->ifa.ifa_scope == (Y)->ifa.ifa_scope && \ string_equal((X)->label, (Y)->label)) #define IP6_ISEQ(X,Y) ((X)->u.sin6_addr.s6_addr32[0] == (Y)->u.sin6_addr.s6_addr32[0] && \ (X)->u.sin6_addr.s6_addr32[1] == (Y)->u.sin6_addr.s6_addr32[1] && \ (X)->u.sin6_addr.s6_addr32[2] == (Y)->u.sin6_addr.s6_addr32[2] && \ (X)->u.sin6_addr.s6_addr32[3] == (Y)->u.sin6_addr.s6_addr32[3] && \ (X)->ifa.ifa_prefixlen == (Y)->ifa.ifa_prefixlen && \ (X)->ifa.ifa_index == (Y)->ifa.ifa_index && \ (X)->ifa.ifa_scope == (Y)->ifa.ifa_scope && \ string_equal((X)->label, (Y)->label)) #define IP_ISEQ(X,Y) (((X) && (Y)) ? ((IP_FAMILY(X) == IP_FAMILY(Y)) ? (IP_IS6(X) ? IP6_ISEQ(X, Y) : IP4_ISEQ(X, Y)) : 0) : (((!(X) && (Y))||((X) && !(Y))) ? 0 : 1)) /* prototypes */ extern void netlink_iplist(list, int); extern void free_ipaddress(void *); extern char *ipaddresstos(ip_address_t *); extern void dump_ipaddress(void *); extern ip_address_t *parse_ipaddress(ip_address_t *, char *); extern void alloc_ipaddress(list, vector_t *, interface_t *); extern void clear_diff_address(list, list); extern void clear_diff_saddresses(void); #endif keepalived-1.2.13/keepalived/include/vrrp_parser.h0000664000175000017500000000220612211121152021763 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vrrp_parser.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_PARSER_H #define _VRRP_PARSER_H /* local include */ #include "vector.h" /* Prototypes */ extern vector_t *vrrp_init_keywords(void); #endif keepalived-1.2.13/keepalived/include/vrrp.h0000644000175000017500000002315012271731313020422 0ustar acassenacassen/* * Soft: Vrrpd is an implementation of VRRPv2 as specified in rfc2338. * VRRP is a protocol which elect a master server on a LAN. If the * master fails, a backup server takes over. * The original implementation has been made by jerome etienne. * * Part: vrrp.c program include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_H #define _VRRP_H /* system include */ #include /* local include */ #include "vrrp_ipaddress.h" #include "vrrp_iproute.h" #include "vrrp_ipsecah.h" #include "vrrp_if.h" #include "vrrp_track.h" #include "timer.h" #include "utils.h" #include "vector.h" #include "list.h" typedef struct _vrrphdr { /* rfc2338.5.1 */ uint8_t vers_type; /* 0-3=type, 4-7=version */ uint8_t vrid; /* virtual router id */ uint8_t priority; /* router priority */ uint8_t naddr; /* address counter */ uint8_t auth_type; /* authentification type */ uint8_t adver_int; /* advertissement interval(in sec) */ uint16_t chksum; /* checksum (ip-like one) */ /* here ip addresses */ /* here authentification infos */ } vrrphdr_t; /* protocol constants */ #define INADDR_VRRP_GROUP 0xe0000012 /* multicast addr - rfc2338.5.2.2 */ #define VRRP_IP_TTL 255 /* in and out pkt ttl -- rfc2338.5.2.3 */ #define IPPROTO_VRRP 112 /* IP protocol number -- rfc2338.5.2.4 */ #define VRRP_VERSION 2 /* current version -- rfc2338.5.3.1 */ #define VRRP_PKT_ADVERT 1 /* packet type -- rfc2338.5.3.2 */ #define VRRP_PRIO_OWNER 255 /* priority of the ip owner -- rfc2338.5.3.4 */ #define VRRP_PRIO_DFL 100 /* default priority -- rfc2338.5.3.4 */ #define VRRP_PRIO_STOP 0 /* priority to stop -- rfc2338.5.3.4 */ #define VRRP_AUTH_NONE 0 /* no authentification -- rfc2338.5.3.6 */ #define VRRP_AUTH_PASS 1 /* password authentification -- rfc2338.5.3.6 */ #define VRRP_AUTH_AH 2 /* AH(IPSec) authentification - rfc2338.5.3.6 */ #define VRRP_ADVER_DFL 1 /* advert. interval (in sec) -- rfc2338.5.3.7 */ #define VRRP_GARP_DELAY (5 * TIMER_HZ) /* Default delay to launch gratuitous arp */ /* * parameters per vrrp sync group. A vrrp_sync_group is a set * of VRRP instances that need to be state sync together. */ typedef struct _vrrp_sgroup { char *gname; /* Group name */ vector_t *iname; /* Set of VRRP instances in this group */ list index_list; /* List of VRRP instances */ int state; /* current stable state */ int global_tracking; /* Use floating priority and scripts * All VRRP must share same tracking conf */ /* State transition notification */ int notify_exec; char *script_backup; char *script_master; char *script_fault; char *script; int smtp_alert; } vrrp_sgroup_t; /* parameters per virtual router -- rfc2338.6.1.2 */ typedef struct _vrrp_t { sa_family_t family; /* AF_INET|AF_INET6 */ char *iname; /* Instance Name */ vrrp_sgroup_t *sync; /* Sync group we belong to */ interface_t *ifp; /* Interface we belong to */ int dont_track_primary; /* If set ignores ifp faults */ int vmac_flags; /* VRRP VMAC flags */ char vmac_ifname[IFNAMSIZ]; /* Name of VRRP VMAC interface */ unsigned int vmac_ifindex; /* ifindex of vmac interface */ list track_ifp; /* Interface state we monitor */ list track_script; /* Script state we monitor */ struct sockaddr_storage saddr; /* Src IP address to use in VRRP IP header */ list unicast_peer; /* List of Unicast peer to send advert to */ char *lvs_syncd_if; /* handle LVS sync daemon state using this * instance FSM & running on specific interface * => eth0 for example. */ int garp_delay; /* Delay to launch gratuitous ARP */ int garp_refresh; /* Next scheduled gratuitous ARP refresh */ timeval_t garp_refresh_timer; /* Next scheduled gratuitous ARP timer */ int vrid; /* virtual id. from 1(!) to 255 */ int base_priority; /* configured priority value */ int effective_priority; /* effective priority value */ int vipset; /* All the vips are set ? */ list vip; /* list of virtual ip addresses */ list evip; /* list of protocol excluded VIPs. * Those VIPs will not be presents into the * VRRP adverts */ list vroutes; /* list of virtual routes */ int adver_int; /* delay between advertisements(in sec) */ int nopreempt; /* true if higher prio does not preempt lower */ long preempt_delay; /* Seconds*TIMER_HZ after startup until * preemption based on higher prio over lower * prio is allowed. 0 means no delay. */ timeval_t preempt_time; /* Time after which preemption can happen */ int state; /* internal state (init/backup/master) */ int init_state; /* the initial state of the instance */ int wantstate; /* user explicitly wants a state (back/mast) */ int fd_in; /* IN socket descriptor */ int fd_out; /* OUT socket descriptor */ int debug; /* Debug level 0-4 */ int quick_sync; /* Will be set when waiting for the other members * in the sync group to become master. * If set the next check will occur in one interval * instead of three intervals. */ /* State transition notification */ int smtp_alert; int notify_exec; char *script_backup; char *script_master; char *script_fault; char *script_stop; char *script; /* rfc2336.6.2 */ uint32_t ms_down_timer; timeval_t sands; /* Sending buffer */ char *send_buffer; /* Allocated send buffer */ int send_buffer_size; /* Authentication data */ int auth_type; /* authentification type. VRRP_AUTH_* */ uint8_t auth_data[8]; /* authentification data */ /* * To have my own ip_id creates collision with kernel ip->id * but it should be ok because the packets are unlikely to be * fragmented (they are non routable and small) * This packet isnt routed, i can check the outgoing MTU * to warn the user only if the outoing mtu is too small */ int ip_id; /* IPSEC AH counter def --rfc2402.3.3.2 */ seq_counter_t *ipsecah_counter; } vrrp_t; /* VRRP state machine -- rfc2338.6.4 */ #define VRRP_STATE_INIT 0 /* rfc2338.6.4.1 */ #define VRRP_STATE_BACK 1 /* rfc2338.6.4.2 */ #define VRRP_STATE_MAST 2 /* rfc2338.6.4.3 */ #define VRRP_STATE_FAULT 3 /* internal */ #define VRRP_STATE_GOTO_MASTER 4 /* internal */ #define VRRP_STATE_LEAVE_MASTER 5 /* internal */ #define VRRP_STATE_GOTO_FAULT 98 /* internal */ #define VRRP_DISPATCHER 99 /* internal */ #define VRRP_MCAST_RETRY 10 /* internal */ #define VRRP_MAX_FSM_STATE 4 /* internal */ /* VRRP packet handling */ #define VRRP_PACKET_OK 0 #define VRRP_PACKET_KO 1 #define VRRP_PACKET_DROP 2 #define VRRP_PACKET_NULL 3 #define VRRP_PACKET_OTHER 4 /* Muliple VRRP on LAN, Identify "other" VRRP */ /* VRRP Packet fixed length */ #define VRRP_MAX_VIP 20 #define VRRP_PACKET_TEMP_LEN 1024 #define VRRP_AUTH_LEN 8 #define VRRP_VIP_TYPE (1 << 0) #define VRRP_EVIP_TYPE (1 << 1) /* VRRP macro */ #define VRRP_IS_BAD_VID(id) ((id)<1 || (id)>255) /* rfc2338.6.1.vrid */ #define VRRP_IS_BAD_PRIORITY(p) ((p)<1 || (p)>255) /* rfc2338.6.1.prio */ #define VRRP_IS_BAD_ADVERT_INT(d) ((d)<1) #define VRRP_IS_BAD_DEBUG_INT(d) ((d)<0 || (d)>4) #define VRRP_IS_BAD_PREEMPT_DELAY(d) ((d)<0 || (d)>TIMER_MAX_SEC) #define VRRP_SEND_BUFFER(V) ((V)->send_buffer) #define VRRP_SEND_BUFFER_SIZE(V) ((V)->send_buffer_size) #define VRRP_TIMER_SKEW(svr) ((256-(svr)->base_priority)*TIMER_HZ/256) #define VRRP_VIP_ISSET(V) ((V)->vipset) #define VRRP_MIN(a, b) ((a) < (b)?(a):(b)) #define VRRP_MAX(a, b) ((a) > (b)?(a):(b)) #define VRRP_PKT_SADDR(V) (((V)->saddr.ss_family) ? ((struct sockaddr_in *) &(V)->saddr)->sin_addr.s_addr : IF_ADDR((V)->ifp)) #define VRRP_IF_ISUP(V) ((IF_ISUP((V)->ifp) || (V)->dont_track_primary) & \ ((!LIST_ISEMPTY((V)->track_ifp)) ? TRACK_ISUP((V)->track_ifp) : 1)) #define VRRP_SCRIPT_ISUP(V) ((!LIST_ISEMPTY((V)->track_script)) ? SCRIPT_ISUP((V)->track_script) : 1) #define VRRP_ISUP(V) (VRRP_IF_ISUP(V) && VRRP_SCRIPT_ISUP(V)) /* prototypes */ extern vrrphdr_t *vrrp_get_header(sa_family_t, char *, int *, uint32_t *); extern int open_vrrp_send_socket(sa_family_t, int, int, int); extern int open_vrrp_socket(sa_family_t, int, int, int); extern int new_vrrp_socket(vrrp_t *); extern void close_vrrp_socket(vrrp_t *); extern void vrrp_send_link_update(vrrp_t *); extern int vrrp_send_adv(vrrp_t *, int); extern int vrrp_state_fault_rx(vrrp_t *, char *, int); extern int vrrp_state_master_rx(vrrp_t *, char *, int); extern int vrrp_state_master_tx(vrrp_t *, const int); extern void vrrp_state_backup(vrrp_t *, char *, int); extern void vrrp_state_goto_master(vrrp_t *); extern void vrrp_state_leave_master(vrrp_t *); extern int vrrp_ipsecah_len(void); extern int vrrp_complete_init(void); extern int vrrp_ipvs_needed(void); extern void shutdown_vrrp_instances(void); extern void clear_diff_vrrp(void); extern void clear_diff_script(void); extern void vrrp_restore_interface(vrrp_t *, int); #endif keepalived-1.2.13/keepalived/include/vrrp_data.h0000664000175000017500000000503012334144310021405 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Dynamic data structure definition. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_DATA_H #define _VRRP_DATA_H /* system includes */ #include #include #include #include #include /* local includes */ #include "list.h" #include "vector.h" #include "scheduler.h" /* * Our instance dispatcher use a socket pool. * That way we handle VRRP protocol type per * physical interface. */ typedef struct _sock { sa_family_t family; int proto; int ifindex; int unicast; int fd_in; int fd_out; thread_t *thread; } sock_t; /* Configuration data root */ typedef struct _vrrp_data { list static_addresses; list static_routes; list vrrp_sync_group; list vrrp; list vrrp_index; list vrrp_index_fd; list vrrp_socket_pool; list vrrp_script; } vrrp_data_t; /* Global Vars exported */ extern vrrp_data_t *vrrp_data; extern vrrp_data_t *old_vrrp_data; extern char *vrrp_buffer; /* prototypes */ extern void alloc_saddress(vector_t *); extern void alloc_sroute(vector_t *); extern void alloc_vrrp_sync_group(char *); extern void alloc_vrrp(char *); extern void alloc_vrrp_unicast_peer(vector_t *); extern void alloc_vrrp_track(vector_t *); extern void alloc_vrrp_script(char *); extern void alloc_vrrp_track_script(vector_t *); extern void alloc_vrrp_vip(vector_t *); extern void alloc_vrrp_evip(vector_t *); extern void alloc_vrrp_vroute(vector_t *); extern void alloc_vrrp_buffer(void); extern void free_vrrp_buffer(void); extern vrrp_data_t *alloc_vrrp_data(void); extern void free_vrrp_data(vrrp_data_t *); extern void dump_vrrp_data(vrrp_data_t *); #endif keepalived-1.2.13/keepalived/include/vrrp_track.h0000664000175000017500000000631312211121152021576 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vrrp_track.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_TRACK_H #define _VRRP_TRACK_H /* global includes */ #include #include #include #include #include /* local includes */ #include "vector.h" #include "list.h" /* Macro definition */ #define TRACK_ISUP(L) (vrrp_tracked_up((L))) #define SCRIPT_ISUP(L) (vrrp_script_up((L))) /* VRRP script tracking defaults */ #define VRRP_SCRIPT_DI 1 /* external script track interval (in sec) */ #define VRRP_SCRIPT_DT 0 /* external script track timeout (in sec) */ #define VRRP_SCRIPT_DW 0 /* external script default weight */ /* VRRP script tracking results. * The result is an integer between 0 and rise-1 to indicate a DOWN state, * or between rise-1 and rise+fall-1 to indicate an UP state. Upon failure, * we decrease result and set it to zero when we pass below rise. Upon * success, we increase result and set it to rise+fall-1 when we pass above * rise-1. */ #define VRRP_SCRIPT_STATUS_DISABLED -3 #define VRRP_SCRIPT_STATUS_INIT_GOOD -2 #define VRRP_SCRIPT_STATUS_INIT -1 /* external script we call to track local processes */ typedef struct _vrrp_script { char *sname; /* instance name */ char *script; /* the command to be called */ long interval; /* interval between script calls */ long timeout; /* seconds before script timeout */ int weight; /* weight associated to this script */ int result; /* result of last call to this script: 0..R-1 = KO, R..R+F-1 = OK */ int inuse; /* how many users have weight>0 ? */ int rise; /* R: how many successes before OK */ int fall; /* F: how many failures before KO */ } vrrp_script_t; /* Tracked script structure definition */ typedef struct _tracked_sc { int weight; /* tracking weight when non-zero */ vrrp_script_t *scr; /* script pointer, cannot be NULL */ } tracked_sc_t; /* prototypes */ extern void dump_track(void *); extern void alloc_track(list, vector_t *); extern void dump_track_script(void *); extern void alloc_track_script(list, vector_t *); extern int vrrp_tracked_up(list); extern void vrrp_log_tracked_down(list); extern int vrrp_tracked_weight(list); extern int vrrp_script_up(list); extern int vrrp_script_weight(list); extern vrrp_script_t *find_script_by_name(char *); #endif keepalived-1.2.13/keepalived/include/global_data.h0000664000175000017500000000404012261277061021665 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Dynamic data structure definition. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _GLOBAL_DATA_H #define _GLOBAL_DATA_H /* system includes */ #include #include #include /* local includes */ #include "list.h" #include "timer.h" /* constants */ #define DEFAULT_SMTP_SERVER 0x7f000001 #define DEFAULT_SMTP_CONNECTION_TIMEOUT (30 * TIMER_HZ) #define DEFAULT_PLUGIN_DIR "/etc/keepalived/plugins" /* email link list */ typedef struct _email { char *addr; } email_t; /* Configuration data root */ typedef struct _data { int linkbeat_use_polling; char *router_id; char *plugin_dir; char *email_from; struct sockaddr_storage smtp_server; long smtp_connection_to; list email; struct sockaddr_storage vrrp_mcast_group4; struct sockaddr_storage vrrp_mcast_group6; #ifdef _WITH_SNMP_ int enable_traps; #endif } data_t; /* Global vars exported */ extern data_t *global_data; /* Global configuration data */ /* Prototypes */ extern void alloc_email(char *); extern data_t *alloc_global_data(void); extern void free_global_data(data_t *); extern void dump_global_data(data_t *); #endif keepalived-1.2.13/keepalived/include/check_http.h0000644000175000017500000000567612334112264021560 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: check_http.c include file. * * Authors: Alexandre Cassen, * Jan Holmberg, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _CHECK_HTTP_H #define _CHECK_HTTP_H /* system includes */ #include #include #include /* local includes */ #include "check_data.h" #include "ipwrapper.h" #include "scheduler.h" #include "layer4.h" #include "list.h" /* Checker argument structure */ /* ssl specific thread arguments defs */ typedef struct _request { char *buffer; char *extracted; int error; int status_code; int len; SSL *ssl; BIO *bio; MD5_CTX context; } request_t; /* http specific thread arguments defs */ typedef struct _http { int retry_it; /* current number of get retry */ int url_it; /* current url checked index */ request_t *req; /* GET buffer and SSL args */ } http_t ; typedef struct _url { char *path; char *digest; int status_code; } url_t; typedef struct _http_checker { int proto; int nb_get_retry; long delay_before_retry; list url; http_t *arg; } http_checker_t; /* global defs */ #define MD5_BUFFER_LENGTH 32 #define GET_BUFFER_LENGTH 2048 #define MAX_BUFFER_LENGTH 4096 #define PROTO_HTTP 0x01 #define PROTO_SSL 0x02 /* GET processing command */ #define REQUEST_TEMPLATE "GET %s HTTP/1.0\r\n" \ "User-Agent:KeepAliveClient\r\n" \ "Host: %s%s\r\n\r\n" #define REQUEST_TEMPLATE_IPV6 "GET %s HTTP/1.0\r\n" \ "User-Agent:KeepAliveClient\r\n" \ "Host: [%s]%s\r\n\r\n" /* macro utility */ #define HTTP_ARG(X) ((X)->arg) #define HTTP_REQ(X) ((X)->req) #define FMT_HTTP_RS(C) FMT_CHK(C) /* Define prototypes */ extern void install_http_check_keyword(void); extern int epilog(thread_t *, int, int, int); extern int timeout_epilog(thread_t *, char *, char *); extern url_t *fetch_next_url(http_checker_t *); extern int http_process_response(request_t *, int); extern int http_handle_response(thread_t *, unsigned char digest[16] , int); #endif keepalived-1.2.13/keepalived/include/daemon.h0000664000175000017500000000240012211121152020655 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Daemon process handling. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _DAEMON_H #define _DAEMON_H /* System includes */ #include #include #include #include #include #include #include #include /* prototype */ extern pid_t xdaemon(int, int, int); #endif keepalived-1.2.13/keepalived/include/vrrp_netlink.h0000664000175000017500000000450012334146463022154 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vrrp_netlink.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_NETLINK_H #define _VRRP_NETLINK_H 1 /* Hack for GNU libc version 2. */ #ifndef MSG_TRUNC #define MSG_TRUNC 0x20 #endif /* MSG_TRUNC */ /* global includes */ #include #include #include /* local includes */ #include "timer.h" /* types definitions */ typedef struct _nl_handle { int fd; struct sockaddr_nl snl; __u32 seq; thread_t *thread; } nl_handle_t; /* Define types */ #define NETLINK_TIMER (30 * TIMER_HZ) #define NLMSG_TAIL(nmsg) ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) /* Global vars exported */ extern nl_handle_t nl_kernel; /* Kernel reflection channel */ extern nl_handle_t nl_cmd; /* Command channel */ /* prototypes */ extern int addattr32(struct nlmsghdr *, int, int, uint32_t); extern int addattr_l(struct nlmsghdr *, int, int, void *, int); extern int rta_addattr_l(struct rtattr *, int, int, const void *, int); extern char *netlink_scope_n2a(int); extern int netlink_scope_a2n(char *); extern int netlink_socket(nl_handle_t *, unsigned long); extern int netlink_close(nl_handle_t *); extern int netlink_talk(nl_handle_t *, struct nlmsghdr *); extern int netlink_interface_lookup(void); extern int netlink_interface_refresh(void); extern void kernel_netlink_init(void); extern void kernel_netlink_close(void); #endif keepalived-1.2.13/keepalived/include/vrrp_vmac.h0000644000175000017500000000273412256127641021443 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vrrp_vmac.c include file. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #ifndef _VRRP_VMAC_H #define _VRRP_VMAC_H /* global includes */ #include #include #include #include #include #include /* local includes */ #include "vrrp.h" #include "vrrp_if.h" /* Defines */ #define VRRP_VMAC_FL_SET (1 << 0) #define VRRP_VMAC_FL_UP (1 << 1) #define VRRP_VMAC_FL_XMITBASE (1 << 2) /* prototypes */ extern int netlink_link_add_vmac(vrrp_t *); extern int netlink_link_del_vmac(vrrp_t *); #endif keepalived-1.2.13/keepalived/vrrp/0000775000175000017500000000000012334417517016636 5ustar acassenacassenkeepalived-1.2.13/keepalived/vrrp/vrrp_ndisc.c0000664000175000017500000001271012211121152021131 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: IPv6 Neighbour Discovery part. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ /* system includes */ #include #include #include /* local includes */ #include "logger.h" #include "memory.h" #include "utils.h" #include "vrrp_ipaddress.h" #include "vrrp_ndisc.h" /* global vars */ char *ndisc_buffer; int ndisc_fd; /* * Neighbour Advertisement sending routine. */ static int ndisc_send_na(ip_address_t *ipaddress) { struct sockaddr_ll sll; int len; /* Build the dst device */ memset(&sll, 0, sizeof (sll)); sll.sll_family = AF_PACKET; memcpy(sll.sll_addr, IF_HWADDR(ipaddress->ifp), ETH_ALEN); sll.sll_halen = ETHERNET_HW_LEN; sll.sll_ifindex = IF_INDEX(ipaddress->ifp); /* Send packet */ len = sendto(ndisc_fd, ndisc_buffer, ETHER_HDR_LEN + sizeof(struct ip6hdr) + sizeof(struct ndhdr) + sizeof(struct nd_opt_hdr) + ETH_ALEN, 0, (struct sockaddr *) &sll, sizeof (sll)); if (len < 0) log_message(LOG_INFO, "VRRP: Error sending ndisc unsolicited neighbour advert on %s", IF_NAME(ipaddress->ifp)); return len; } /* * ICMPv6 Checksuming. */ static uint32_t ndisc_icmp6_cksum(const struct ip6hdr *ip6, const struct icmp6hdr *icp, uint32_t len) { size_t i; register const uint16_t *sp; uint32_t sum; union { struct { struct in6_addr ph_src; struct in6_addr ph_dst; uint32_t ph_len; uint8_t ph_zero[3]; uint8_t ph_nxt; } ph; uint16_t pa[20]; } phu; /* pseudo-header */ memset(&phu, 0, sizeof(phu)); phu.ph.ph_src = ip6->saddr; phu.ph.ph_dst = ip6->daddr; phu.ph.ph_len = htonl(len); phu.ph.ph_nxt = IPPROTO_ICMPV6; sum = 0; for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) sum += phu.pa[i]; sp = (const uint16_t *)icp; for (i = 0; i < (len & ~1); i += 2) sum += *sp++; if (len & 1) sum += htons((*(const uint8_t *)sp) << 8); while (sum > 0xffff) sum = (sum & 0xffff) + (sum >> 16); sum = ~sum & 0xffff; return (sum); } /* * Build an unsolicited Neighbour Advertisement. * As explained in rfc4861.4.4, a node sends unsolicited * Neighbor Advertisements in order to (unreliably) propagate * new information quickly. */ int ndisc_send_unsolicited_na(ip_address_t *ipaddress) { struct ether_header *eth = (struct ether_header *) ndisc_buffer; struct ip6hdr *ip6h = (struct ip6hdr *) ((char *)eth + ETHER_HDR_LEN); struct ndhdr *ndh = (struct ndhdr*) ((char *)ip6h + sizeof(struct ip6hdr)); struct icmp6hdr *icmp6h = &ndh->icmph; struct nd_opt_hdr *nd_opt_h = (struct nd_opt_hdr *) ((char *)ndh + sizeof(struct ndhdr)); char *nd_opt_lladdr = (char *) ((char *)nd_opt_h + sizeof(struct nd_opt_hdr)); char *lladdr = (char *) IF_HWADDR(ipaddress->ifp); int len; /* Ethernet header: * Destination ethernet address MUST use specific address Mapping * as specified in rfc2464.7 Address Mapping for */ memset(eth->ether_dhost, 0, ETH_ALEN); eth->ether_dhost[0] = eth->ether_dhost[1] = 0x33; eth->ether_dhost[5] = 1; memcpy(eth->ether_shost, lladdr, ETH_ALEN); eth->ether_type = htons(ETHERTYPE_IPV6); /* IPv6 Header */ ip6h->version = 6; ip6h->payload_len = htons(sizeof(struct ndhdr) + sizeof(struct nd_opt_hdr) + ETH_ALEN); ip6h->nexthdr = NEXTHDR_ICMP; ip6h->hop_limit = NDISC_HOPLIMIT; ip6h->saddr = ipaddress->u.sin6_addr; ip6h->daddr.s6_addr16[0] = htons(0xff02); ip6h->daddr.s6_addr16[7] = htons(1); /* ICMPv6 Header */ icmp6h->icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT; /* Override flag is set to indicate that the advertisement * should override an existing cache entry and update the * cached link-layer address. */ icmp6h->icmp6_override = 1; ndh->target = ipaddress->u.sin6_addr; /* NDISC Option header */ nd_opt_h->nd_opt_type = ND_OPT_TARGET_LL_ADDR; nd_opt_h->nd_opt_len = 1; memcpy(nd_opt_lladdr, lladdr, ETH_ALEN); /* Compute checksum */ icmp6h->icmp6_cksum = ndisc_icmp6_cksum(ip6h, icmp6h, sizeof(struct ndhdr) + sizeof(struct nd_opt_hdr) + ETH_ALEN); /* Send the neighbor advertisement message */ len = ndisc_send_na(ipaddress); /* Cleanup room for next round */ memset(ndisc_buffer, 0, ETHER_HDR_LEN + sizeof(struct ip6hdr) + sizeof(struct ndhdr) + sizeof(struct nd_opt_hdr) + ETH_ALEN); return len; } /* * Neighbour Discovery init/close */ void ndisc_init(void) { /* Initalize shared buffer */ ndisc_buffer = (char *) MALLOC(ETHER_HDR_LEN + sizeof(struct ip6hdr) + sizeof(struct ndhdr) + sizeof(struct nd_opt_hdr) + ETH_ALEN); /* Create the socket descriptor */ ndisc_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IPV6)); } void ndisc_close(void) { FREE(ndisc_buffer); close(ndisc_fd); } keepalived-1.2.13/keepalived/vrrp/vrrp_ipaddress.c0000644000175000017500000002242512256127641022033 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: NETLINK IPv4 address manipulation. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ /* local include */ #include "vrrp_ipaddress.h" #include "vrrp_netlink.h" #include "vrrp_data.h" #include "logger.h" #include "memory.h" #include "utils.h" /* Add/Delete IP address to a specific interface_t */ static int netlink_ipaddress(ip_address_t *ipaddress, int cmd) { struct ifa_cacheinfo cinfo; char *addr_str; int status = 1; struct { struct nlmsghdr n; struct ifaddrmsg ifa; char buf[256]; } req; memset(&req, 0, sizeof (req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifaddrmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = cmd ? RTM_NEWADDR : RTM_DELADDR; req.ifa = ipaddress->ifa; if (IP_IS6(ipaddress)) { /* Mark IPv6 address as deprecated (rfc3484) in order to prevent * using VRRP VIP as source address in healthchecking use cases. */ if (ipaddress->ifa.ifa_prefixlen == 128) { memset(&cinfo, 0, sizeof(cinfo)); cinfo.ifa_prefered = 0; cinfo.ifa_valid = 0xFFFFFFFFU; addr_str = ipaddresstos(ipaddress); log_message(LOG_INFO, "%s has a prefix length of 128, setting " "preferred_lft to 0\n", addr_str); FREE(addr_str); addattr_l(&req.n, sizeof(req), IFA_CACHEINFO, &cinfo, sizeof(cinfo)); } /* Disable, per VIP, Duplicate Address Detection algorithm (DAD). * Using the nodad flag has the following benefits: * * (1) The address becomes immediately usable after they're * configured. * (2) In the case of a temporary layer-2 / split-brain problem * we can avoid that the active VIP transitions into the * dadfailed phase and stays there forever - leaving us * without service. HA/VRRP setups have their own "DAD"-like * functionality, so it's not really needed from the IPv6 stack. */ #ifdef IFA_F_NODAD req.ifa.ifa_flags |= IFA_F_NODAD; #endif addattr_l(&req.n, sizeof(req), IFA_LOCAL, &ipaddress->u.sin6_addr, sizeof(ipaddress->u.sin6_addr)); } else { addattr_l(&req.n, sizeof(req), IFA_LOCAL, &ipaddress->u.sin.sin_addr, sizeof(ipaddress->u.sin.sin_addr)); if (ipaddress->u.sin.sin_brd.s_addr) addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &ipaddress->u.sin.sin_brd, sizeof(ipaddress->u.sin.sin_brd)); } if (ipaddress->label) addattr_l(&req.n, sizeof (req), IFA_LABEL, ipaddress->label, strlen(ipaddress->label) + 1); if (netlink_talk(&nl_cmd, &req.n) < 0) status = -1; return status; } /* Add/Delete a list of IP addresses */ void netlink_iplist(list ip_list, int cmd) { ip_address_t *ipaddr; element e; /* No addresses in this list */ if (LIST_ISEMPTY(ip_list)) return; /* * If "--dont-release-vrrp" (debug & 8) is set then try to release * addresses that may be there, even if we didn't set them. */ for (e = LIST_HEAD(ip_list); e; ELEMENT_NEXT(e)) { ipaddr = ELEMENT_DATA(e); if ((cmd && !ipaddr->set) || (!cmd && (ipaddr->set || debug & 8))) { if (netlink_ipaddress(ipaddr, cmd) > 0) ipaddr->set = (cmd) ? 1 : 0; else ipaddr->set = 0; } } } /* IP address dump/allocation */ void free_ipaddress(void *if_data) { ip_address_t *ipaddr = if_data; FREE_PTR(ipaddr->label); FREE(ipaddr); } char * ipaddresstos(ip_address_t *ipaddress) { char *addr_str = (char *) MALLOC(INET6_ADDRSTRLEN); if (IP_IS6(ipaddress)) { inet_ntop(AF_INET6, &ipaddress->u.sin6_addr, addr_str, INET6_ADDRSTRLEN); } else { inet_ntop(AF_INET, &ipaddress->u.sin.sin_addr, addr_str, INET_ADDRSTRLEN); } return addr_str; } void dump_ipaddress(void *if_data) { ip_address_t *ipaddr = if_data; char *broadcast = (char *) MALLOC(INET_ADDRSTRLEN + 5); char *addr_str; addr_str = ipaddresstos(ipaddr); if (!IP_IS6(ipaddr) && ipaddr->u.sin.sin_brd.s_addr) { snprintf(broadcast, 21, " brd %s", inet_ntop2(ipaddr->u.sin.sin_brd.s_addr)); } log_message(LOG_INFO, " %s/%d%s dev %s scope %s%s%s" , addr_str , ipaddr->ifa.ifa_prefixlen , broadcast , IF_NAME(ipaddr->ifp) , netlink_scope_n2a(ipaddr->ifa.ifa_scope) , ipaddr->label ? " label " : "" , ipaddr->label ? ipaddr->label : ""); FREE(broadcast); FREE(addr_str); } ip_address_t * parse_ipaddress(ip_address_t *ip_address, char *str) { ip_address_t *new = ip_address; void *addr; char *p; /* No ip address, allocate a brand new one */ if (!new) { new = (ip_address_t *) MALLOC(sizeof(ip_address_t)); } /* Handle the specials */ if (!strcmp(str, "default")) { new->ifa.ifa_family = AF_INET; return new; } else if (!strcmp(str, "default6")) { new->ifa.ifa_family = AF_INET6; return new; } /* Parse ip address */ new->ifa.ifa_family = (strchr(str, ':')) ? AF_INET6 : AF_INET; new->ifa.ifa_prefixlen = (IP_IS6(new)) ? 128 : 32; p = strchr(str, '/'); if (p) { new->ifa.ifa_prefixlen = atoi(p + 1); *p = 0; } addr = (IP_IS6(new)) ? (void *) &new->u.sin6_addr : (void *) &new->u.sin.sin_addr; if (!inet_pton(IP_FAMILY(new), str, addr)) { log_message(LOG_INFO, "VRRP parsed invalid IP %s. skipping IP...", str); FREE(new); new = NULL; } /* Restore slash */ if (p) { *p = '/'; } return new; } void alloc_ipaddress(list ip_list, vector_t *strvec, interface_t *ifp) { ip_address_t *new; interface_t *ifp_local; char *str; int i = 0, addr_idx =0; new = (ip_address_t *) MALLOC(sizeof(ip_address_t)); if (ifp) { new->ifa.ifa_index = IF_INDEX(ifp); new->ifp = ifp; } else { ifp_local = if_get_by_ifname(DFLT_INT); if (!ifp_local) { log_message(LOG_INFO, "Default interface " DFLT_INT " does not exist and no interface specified. " "Skip VRRP address."); FREE(new); return; } new->ifa.ifa_index = IF_INDEX(ifp_local); new->ifp = ifp_local; } /* FMT parse */ while (i < vector_size(strvec)) { str = vector_slot(strvec, i); /* cmd parsing */ if (!strcmp(str, "dev")) { ifp_local = if_get_by_ifname(vector_slot(strvec, ++i)); if (!ifp_local) { log_message(LOG_INFO, "VRRP is trying to assign VIP to unknown %s" " interface !!! go out and fix your conf !!!", (char *)vector_slot(strvec, i)); FREE(new); return; } new->ifa.ifa_index = IF_INDEX(ifp_local); new->ifp = ifp_local; } else if (!strcmp(str, "scope")) { new->ifa.ifa_scope = netlink_scope_a2n(vector_slot(strvec, ++i)); } else if (!strcmp(str, "broadcast") || !strcmp(str, "brd")) { if (IP_IS6(new)) { log_message(LOG_INFO, "VRRP is trying to assign a broadcast %s to the IPv6 address %s !!?? " "WTF... skipping VIP..." , vector_slot(strvec, i), vector_slot(strvec, addr_idx)); FREE(new); return; } else if (!inet_pton(AF_INET, vector_slot(strvec, ++i), &new->u.sin.sin_brd)) { log_message(LOG_INFO, "VRRP is trying to assign invalid broadcast %s. " "skipping VIP...", vector_slot(strvec, i)); FREE(new); return; } } else if (!strcmp(str, "label")) { new->label = MALLOC(IFNAMSIZ); strncpy(new->label, vector_slot(strvec, ++i), IFNAMSIZ); } else { if (!parse_ipaddress(new, str)) return; addr_idx = i; } i++; } list_add(ip_list, new); } /* Find an address in a list */ int address_exist(list l, ip_address_t *ipaddress) { ip_address_t *ipaddr; element e; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { ipaddr = ELEMENT_DATA(e); if (IP_ISEQ(ipaddr, ipaddress)) { ipaddr->set = ipaddress->set; return 1; } } return 0; } /* Clear diff addresses */ void clear_diff_address(list l, list n) { ip_address_t *ipaddr; element e; char *addr_str; void *addr; /* No addresses in previous conf */ if (LIST_ISEMPTY(l)) return; /* All addresses removed */ if (LIST_ISEMPTY(n)) { log_message(LOG_INFO, "Removing a VIP|E-VIP block"); netlink_iplist(l, IPADDRESS_DEL); return; } addr_str = (char *) MALLOC(41); for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { ipaddr = ELEMENT_DATA(e); if (!address_exist(n, ipaddr) && ipaddr->set) { addr = (IP_IS6(ipaddr)) ? (void *) &ipaddr->u.sin6_addr : (void *) &ipaddr->u.sin.sin_addr; inet_ntop(IP_FAMILY(ipaddr), addr, addr_str, 41); log_message(LOG_INFO, "ip address %s/%d dev %s, no longer exist" , addr_str , ipaddr->ifa.ifa_prefixlen , IF_NAME(if_get_by_ifindex(ipaddr->ifa.ifa_index))); netlink_ipaddress(ipaddr, IPADDRESS_DEL); } } FREE(addr_str); } /* Clear static ip address */ void clear_diff_saddresses(void) { clear_diff_address(old_vrrp_data->static_addresses, vrrp_data->static_addresses); } keepalived-1.2.13/keepalived/vrrp/vrrp_netlink.c0000644000175000017500000004347212334210477021523 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: NETLINK kernel command channel. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ /* global include */ #include #include #include #include #include #include #include #include #include #include #include #include /* local include */ #include "check_api.h" #include "vrrp_netlink.h" #include "vrrp_if.h" #include "logger.h" #include "memory.h" #include "scheduler.h" #include "utils.h" /* Global vars */ nl_handle_t nl_kernel; /* Kernel reflection channel */ nl_handle_t nl_cmd; /* Command channel */ /* Create a socket to netlink interface_t */ int netlink_socket(nl_handle_t *nl, unsigned long groups) { socklen_t addr_len; int ret; memset(nl, 0, sizeof (*nl)); nl->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (nl->fd < 0) { log_message(LOG_INFO, "Netlink: Cannot open netlink socket : (%s)", strerror(errno)); return -1; } ret = fcntl(nl->fd, F_SETFL, O_NONBLOCK); if (ret < 0) { log_message(LOG_INFO, "Netlink: Cannot set netlink socket flags : (%s)", strerror(errno)); close(nl->fd); return -1; } memset(&nl->snl, 0, sizeof (nl->snl)); nl->snl.nl_family = AF_NETLINK; nl->snl.nl_groups = groups; ret = bind(nl->fd, (struct sockaddr *) &nl->snl, sizeof (nl->snl)); if (ret < 0) { log_message(LOG_INFO, "Netlink: Cannot bind netlink socket : (%s)", strerror(errno)); close(nl->fd); return -1; } addr_len = sizeof (nl->snl); ret = getsockname(nl->fd, (struct sockaddr *) &nl->snl, &addr_len); if (ret < 0 || addr_len != sizeof (nl->snl)) { log_message(LOG_INFO, "Netlink: Cannot getsockname : (%s)", strerror(errno)); close(nl->fd); return -1; } if (nl->snl.nl_family != AF_NETLINK) { log_message(LOG_INFO, "Netlink: Wrong address family %d", nl->snl.nl_family); close(nl->fd); return -1; } nl->seq = time(NULL); /* Set default rcvbuf size */ if_setsockopt_rcvbuf(&nl->fd, IF_DEFAULT_BUFSIZE); if (nl->fd < 0) return -1; return ret; } /* Close a netlink socket */ int netlink_close(nl_handle_t *nl) { /* First of all release pending thread */ thread_cancel(nl->thread); close(nl->fd); return 0; } /* Set netlink socket channel as blocking */ int netlink_set_block(nl_handle_t *nl, int *flags) { if ((*flags = fcntl(nl->fd, F_GETFL, 0)) < 0) { log_message(LOG_INFO, "Netlink: Cannot F_GETFL socket : (%s)", strerror(errno)); return -1; } *flags &= ~O_NONBLOCK; if (fcntl(nl->fd, F_SETFL, *flags) < 0) { log_message(LOG_INFO, "Netlink: Cannot F_SETFL socket : (%s)", strerror(errno)); return -1; } return 0; } /* Set netlink socket channel as non-blocking */ int netlink_set_nonblock(nl_handle_t *nl, int *flags) { *flags |= O_NONBLOCK; if (fcntl(nl->fd, F_SETFL, *flags) < 0) { log_message(LOG_INFO, "Netlink: Cannot F_SETFL socket : (%s)", strerror(errno)); return -1; } return 0; } /* iproute2 utility function */ int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data) { int len = RTA_LENGTH(4); struct rtattr *rta; if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) return -1; rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; memcpy(RTA_DATA(rta), &data, 4); n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; return 0; } int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) { int len = RTA_LENGTH(alen); struct rtattr *rta; if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) return -1; rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN(n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; memcpy(RTA_DATA(rta), data, alen); n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; return 0; } int rta_addattr_l(struct rtattr *rta, int maxlen, int type, const void *data, int alen) { struct rtattr *subrta; int len = RTA_LENGTH(alen); if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) { return -1; } subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); subrta->rta_type = type; subrta->rta_len = len; memcpy(RTA_DATA(subrta), data, alen); rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len); return 0; } static void parse_rtattr(struct rtattr **tb, int max, struct rtattr *rta, int len) { while (RTA_OK(rta, len)) { if (rta->rta_type <= max) tb[rta->rta_type] = rta; rta = RTA_NEXT(rta, len); } } char * netlink_scope_n2a(int scope) { if (scope == 0) return "global"; if (scope == 255) return "nowhere"; if (scope == 254) return "host"; if (scope == 253) return "link"; if (scope == 200) return "site"; return "unknown"; } int netlink_scope_a2n(char *scope) { if (!strcmp(scope, "global")) return 0; if (!strcmp(scope, "nowhere")) return 255; if (!strcmp(scope, "host")) return 254; if (!strcmp(scope, "link")) return 253; if (!strcmp(scope, "site")) return 200; return -1; } /* * Reflect base interface flags on VMAC interface. * VMAC interfaces should never update it own flags, only be reflected * by the base interface flags. */ static void vmac_reflect_flags(struct ifinfomsg *ifi) { interface_t *ifp; /* find the VMAC interface (if any) */ ifp = if_get_by_vmac_base_ifindex(ifi->ifi_index); /* if found, reflect base interface flags on VMAC interface */ if (ifp) { ifp->flags = ifi->ifi_flags; } } /* Our netlink parser */ static int netlink_parse_info(int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), nl_handle_t *nl, struct nlmsghdr *n) { int status; int ret = 0; int error; while (1) { char buf[4096]; struct iovec iov = { buf, sizeof buf }; struct sockaddr_nl snl; struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 }; struct nlmsghdr *h; status = recvmsg(nl->fd, &msg, 0); if (status < 0) { if (errno == EINTR) continue; if (errno == EWOULDBLOCK || errno == EAGAIN) break; log_message(LOG_INFO, "Netlink: Received message overrun (%m)"); continue; } if (status == 0) { log_message(LOG_INFO, "Netlink: EOF"); return -1; } if (msg.msg_namelen != sizeof snl) { log_message(LOG_INFO, "Netlink: Sender address length error: length %d", msg.msg_namelen); return -1; } for (h = (struct nlmsghdr *) buf; NLMSG_OK(h, status); h = NLMSG_NEXT(h, status)) { /* Finish of reading. */ if (h->nlmsg_type == NLMSG_DONE) return ret; /* Error handling. */ if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA(h); /* * If error == 0 then this is a netlink ACK. * return if not related to multipart message. */ if (err->error == 0) { if (!(h->nlmsg_flags & NLM_F_MULTI)) return 0; continue; } if (h->nlmsg_len < NLMSG_LENGTH(sizeof (struct nlmsgerr))) { log_message(LOG_INFO, "Netlink: error: message truncated"); return -1; } if (n && (err->error == -EEXIST) && ((n->nlmsg_type == RTM_NEWROUTE) || (n->nlmsg_type == RTM_NEWADDR))) return 0; log_message(LOG_INFO, "Netlink: error: %s, type=(%u), seq=%u, pid=%d", strerror(-err->error), err->msg.nlmsg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid); return -1; } /* Skip unsolicited messages from cmd channel */ if (nl != &nl_cmd && h->nlmsg_pid == nl_cmd.snl.nl_pid) continue; error = (*filter) (&snl, h); if (error < 0) { log_message(LOG_INFO, "Netlink: filter function error"); ret = error; } } /* After error care. */ if (msg.msg_flags & MSG_TRUNC) { log_message(LOG_INFO, "Netlink: error: message truncated"); continue; } if (status) { log_message(LOG_INFO, "Netlink: error: data remnant size %d", status); return -1; } } return ret; } /* Out talk filter */ static int netlink_talk_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) { log_message(LOG_INFO, "Netlink: ignoring message type 0x%04x", h->nlmsg_type); return 0; } /* send message to netlink kernel socket, then receive response */ int netlink_talk(nl_handle_t *nl, struct nlmsghdr *n) { int status; int ret, flags; struct sockaddr_nl snl; struct iovec iov = { (void *) n, n->nlmsg_len }; struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 }; memset(&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; n->nlmsg_seq = ++nl->seq; /* Request Netlink acknowledgement */ n->nlmsg_flags |= NLM_F_ACK; /* Send message to netlink interface. */ status = sendmsg(nl->fd, &msg, 0); if (status < 0) { log_message(LOG_INFO, "Netlink: sendmsg() error: %s", strerror(errno)); return -1; } /* Set blocking flag */ ret = netlink_set_block(nl, &flags); if (ret < 0) log_message(LOG_INFO, "Netlink: Warning, couldn't set " "blocking flag to netlink socket..."); status = netlink_parse_info(netlink_talk_filter, nl, n); /* Restore previous flags */ if (ret == 0) netlink_set_nonblock(nl, &flags); return status; } /* Fetch a specific type information from netlink kernel */ static int netlink_request(nl_handle_t *nl, int family, int type) { int status; struct sockaddr_nl snl; struct { struct nlmsghdr nlh; struct rtgenmsg g; } req; /* Cleanup the room */ memset(&snl, 0, sizeof (snl)); snl.nl_family = AF_NETLINK; req.nlh.nlmsg_len = sizeof (req); req.nlh.nlmsg_type = type; req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; req.nlh.nlmsg_pid = 0; req.nlh.nlmsg_seq = ++nl->seq; req.g.rtgen_family = family; status = sendto(nl->fd, (void *) &req, sizeof (req) , 0, (struct sockaddr *) &snl, sizeof (snl)); if (status < 0) { log_message(LOG_INFO, "Netlink: sendto() failed: %s", strerror(errno)); return -1; } return 0; } /* Netlink interface link lookup filter */ static int netlink_if_link_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) { struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; interface_t *ifp; int i, len; char *name; ifi = NLMSG_DATA(h); if (h->nlmsg_type != RTM_NEWLINK) return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifinfomsg)); if (len < 0) return -1; /* Interface name lookup */ memset(tb, 0, sizeof (tb)); parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); if (tb[IFLA_IFNAME] == NULL) return -1; name = (char *) RTA_DATA(tb[IFLA_IFNAME]); /* Return if loopback */ if (ifi->ifi_type == ARPHRD_LOOPBACK) return 0; /* Skip it if already exist */ ifp = if_get_by_ifname(name); if (ifp) { if (!ifp->vmac) { vmac_reflect_flags(ifi); ifp->flags = ifi->ifi_flags; } return 0; } /* Fill the interface structure */ ifp = (interface_t *) MALLOC(sizeof(interface_t)); memcpy(ifp->ifname, name, strlen(name)); ifp->ifindex = ifi->ifi_index; ifp->mtu = *(int *) RTA_DATA(tb[IFLA_MTU]); ifp->hw_type = ifi->ifi_type; if (!ifp->vmac) { vmac_reflect_flags(ifi); ifp->flags = ifi->ifi_flags; ifp->base_ifindex = ifi->ifi_index; } if (tb[IFLA_ADDRESS]) { int hw_addr_len = RTA_PAYLOAD(tb[IFLA_ADDRESS]); if (hw_addr_len > IF_HWADDR_MAX) log_message(LOG_ERR, "MAC address for %s is too large: %d", name, hw_addr_len); else { ifp->hw_addr_len = hw_addr_len; memcpy(ifp->hw_addr, RTA_DATA(tb[IFLA_ADDRESS]), hw_addr_len); for (i = 0; i < hw_addr_len; i++) if (ifp->hw_addr[i] != 0) break; if (i == hw_addr_len) ifp->hw_addr_len = 0; else ifp->hw_addr_len = hw_addr_len; } } /* Queue this new interface_t */ if_add_queue(ifp); return 0; } /* * Netlink interface address lookup filter * We need to handle multiple primary address and * multiple secondary address to the same interface. */ static int netlink_if_address_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) { struct ifaddrmsg *ifa; struct rtattr *tb[IFA_MAX + 1]; interface_t *ifp; int len; void *addr; ifa = NLMSG_DATA(h); /* Only IPV4 are valid us */ if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) return 0; if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR) return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifaddrmsg)); if (len < 0) return -1; memset(tb, 0, sizeof (tb)); parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len); /* Fetch interface_t */ ifp = if_get_by_ifindex(ifa->ifa_index); if (!ifp) return 0; if (tb[IFA_LOCAL] == NULL) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (tb[IFA_ADDRESS] == NULL) tb[IFA_ADDRESS] = tb[IFA_LOCAL]; /* local interface address */ addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL); if (addr == NULL) return -1; /* If no address is set on interface then set the first time */ if (ifa->ifa_family == AF_INET) { if (!ifp->sin_addr.s_addr) ifp->sin_addr = *(struct in_addr *) addr; } else { if (!ifp->sin6_addr.s6_addr16[0] && ifa->ifa_scope == RT_SCOPE_LINK) ifp->sin6_addr = *(struct in6_addr *) addr; } #ifdef _WITH_LVS_ /* Refresh checkers state */ update_checker_activity(ifa->ifa_family, addr, (h->nlmsg_type == RTM_NEWADDR) ? 1 : 0); #endif return 0; } /* Interfaces lookup bootstrap function */ int netlink_interface_lookup(void) { nl_handle_t nlh; int status = 0; int ret, flags; if (netlink_socket(&nlh, 0) < 0) return -1; /* Set blocking flag */ ret = netlink_set_block(&nlh, &flags); if (ret < 0) log_message(LOG_INFO, "Netlink: Warning, couldn't set " "blocking flag to netlink socket..."); /* Interface lookup */ if (netlink_request(&nlh, AF_PACKET, RTM_GETLINK) < 0) { status = -1; goto end_int; } status = netlink_parse_info(netlink_if_link_filter, &nlh, NULL); end_int: netlink_close(&nlh); return status; } /* Adresses lookup bootstrap function */ static int netlink_address_lookup(void) { nl_handle_t nlh; int status = 0; int ret, flags; if (netlink_socket(&nlh, 0) < 0) return -1; /* Set blocking flag */ ret = netlink_set_block(&nlh, &flags); if (ret < 0) log_message(LOG_INFO, "Netlink: Warning, couldn't set " "blocking flag to netlink socket..."); /* IPv4 Address lookup */ if (netlink_request(&nlh, AF_INET, RTM_GETADDR) < 0) { status = -1; goto end_addr; } status = netlink_parse_info(netlink_if_address_filter, &nlh, NULL); /* IPv6 Address lookup */ if (netlink_request(&nlh, AF_INET6, RTM_GETADDR) < 0) { status = -1; goto end_addr; } status = netlink_parse_info(netlink_if_address_filter, &nlh, NULL); end_addr: netlink_close(&nlh); return status; } /* Netlink flag Link update */ static int netlink_reflect_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) { struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; interface_t *ifp; int len; ifi = NLMSG_DATA(h); if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifinfomsg)); if (len < 0) return -1; /* Interface name lookup */ memset(tb, 0, sizeof (tb)); parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); if (tb[IFLA_IFNAME] == NULL) return -1; /* ignore loopback device */ if (ifi->ifi_type == ARPHRD_LOOPBACK) return 0; /* find the interface_t */ ifp = if_get_by_ifindex(ifi->ifi_index); if (!ifp) return -1; /* * Update flags. * VMAC interfaces should never update it own flags, only be reflected * by the base interface flags. */ if (!ifp->vmac) { vmac_reflect_flags(ifi); ifp->flags = ifi->ifi_flags; } return 0; } /* Netlink kernel message reflection */ static int netlink_broadcast_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) { switch (h->nlmsg_type) { case RTM_NEWLINK: case RTM_DELLINK: return netlink_reflect_filter(snl, h); break; case RTM_NEWADDR: case RTM_DELADDR: return netlink_if_address_filter(snl, h); break; default: log_message(LOG_INFO, "Kernel is reflecting an unknown netlink nlmsg_type: %d", h->nlmsg_type); break; } return 0; } int kernel_netlink(thread_t * thread) { nl_handle_t *nl = THREAD_ARG(thread); if (thread->type != THREAD_READ_TIMEOUT) netlink_parse_info(netlink_broadcast_filter, nl, NULL); nl->thread = thread_add_read(master, kernel_netlink, nl, nl->fd, NETLINK_TIMER); return 0; } void kernel_netlink_init(void) { unsigned long groups; /* Start with a netlink address lookup */ netlink_address_lookup(); /* * Prepare netlink kernel broadcast channel * subscribtion. We subscribe to LINK and ADDR * netlink broadcast messages. */ groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR; netlink_socket(&nl_kernel, groups); if (nl_kernel.fd > 0) { log_message(LOG_INFO, "Registering Kernel netlink reflector"); nl_kernel.thread = thread_add_read(master, kernel_netlink, &nl_kernel, nl_kernel.fd, NETLINK_TIMER); } else log_message(LOG_INFO, "Error while registering Kernel netlink reflector channel"); /* Prepare netlink command channel. */ netlink_socket(&nl_cmd, 0); if (nl_cmd.fd > 0) log_message(LOG_INFO, "Registering Kernel netlink command channel"); else log_message(LOG_INFO, "Error while registering Kernel netlink cmd channel"); } void kernel_netlink_close(void) { netlink_close(&nl_kernel); netlink_close(&nl_cmd); } keepalived-1.2.13/keepalived/vrrp/vrrp_daemon.c0000644000175000017500000001635412334173525021323 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: VRRP child process handling. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "vrrp_daemon.h" #include "vrrp_scheduler.h" #include "vrrp_if.h" #include "vrrp_arp.h" #include "vrrp_ndisc.h" #include "vrrp_netlink.h" #include "vrrp_ipaddress.h" #include "vrrp_iproute.h" #include "vrrp_parser.h" #include "vrrp_data.h" #include "vrrp.h" #include "global_data.h" #include "pidfile.h" #include "daemon.h" #include "logger.h" #include "signals.h" #ifdef _WITH_LVS_ #include "ipvswrapper.h" #endif #ifdef _WITH_SNMP_ #include "vrrp_snmp.h" #endif #include "list.h" #include "main.h" #include "memory.h" #include "parser.h" extern char *vrrp_pidfile; /* Daemon stop sequence */ static void stop_vrrp(void) { signal_handler_destroy(); if (!(debug & 8)) shutdown_vrrp_instances(); /* Clear static entries */ netlink_rtlist(vrrp_data->static_routes, IPROUTE_DEL); netlink_iplist(vrrp_data->static_addresses, IPADDRESS_DEL); #ifdef _WITH_SNMP_ if (snmp) vrrp_snmp_agent_close(); #endif /* Stop daemon */ pidfile_rm(vrrp_pidfile); #ifdef _WITH_LVS_ if (vrrp_ipvs_needed()) { /* Clean ipvs related */ ipvs_stop(); } #endif /* Clean data */ free_global_data(global_data); vrrp_dispatcher_release(vrrp_data); free_vrrp_data(vrrp_data); free_vrrp_buffer(); free_interface_queue(); kernel_netlink_close(); thread_destroy_master(master); gratuitous_arp_close(); ndisc_close(); #ifdef _DEBUG_ keepalived_free_final("VRRP Child process"); #endif /* * Reached when terminate signal catched. * finally return to parent process. */ closelog(); exit(0); } /* Daemon init sequence */ static void start_vrrp(void) { /* Initialize sub-system */ init_interface_queue(); kernel_netlink_init(); gratuitous_arp_init(); ndisc_init(); #ifdef _WITH_SNMP_ if (!reload && snmp) vrrp_snmp_agent_init(); #endif /* Parse configuration file */ global_data = alloc_global_data(); vrrp_data = alloc_vrrp_data(); alloc_vrrp_buffer(); init_data(conf_file, vrrp_init_keywords); if (!vrrp_data) { stop_vrrp(); return; } #ifdef _WITH_LVS_ if (vrrp_ipvs_needed()) { /* Initialize ipvs related */ if (ipvs_start() != IPVS_SUCCESS) { stop_vrrp(); return; } } #endif if (reload) { clear_diff_saddresses(); clear_diff_sroutes(); clear_diff_vrrp(); clear_diff_script(); } /* Complete VRRP initialization */ if (!vrrp_complete_init()) { if (vrrp_ipvs_needed()) { stop_vrrp(); } return; } /* Post initializations */ log_message(LOG_INFO, "Configuration is using : %lu Bytes", mem_allocated); /* Set static entries */ netlink_iplist(vrrp_data->static_addresses, IPADDRESS_ADD); netlink_rtlist(vrrp_data->static_routes, IPROUTE_ADD); /* Dump configuration */ if (debug & 4) { dump_global_data(global_data); dump_vrrp_data(vrrp_data); } /* Initialize linkbeat */ init_interface_linkbeat(); /* Init & start the VRRP packet dispatcher */ thread_add_event(master, vrrp_dispatcher_init, NULL, VRRP_DISPATCHER); } /* Reload handler */ int reload_vrrp_thread(thread_t * thread); void sighup_vrrp(void *v, int sig) { thread_add_event(master, reload_vrrp_thread, NULL, 0); } /* Terminate handler */ void sigend_vrrp(void *v, int sig) { if (master) thread_add_terminate_event(master); } /* VRRP Child signal handling */ void vrrp_signal_init(void) { signal_handler_init(); signal_set(SIGHUP, sighup_vrrp, NULL); signal_set(SIGINT, sigend_vrrp, NULL); signal_set(SIGTERM, sigend_vrrp, NULL); signal_ignore(SIGPIPE); } /* Reload thread */ int reload_vrrp_thread(thread_t * thread) { /* set the reloading flag */ SET_RELOAD; /* Signal handling */ signal_reset(); signal_handler_destroy(); /* Destroy master thread */ vrrp_dispatcher_release(vrrp_data); kernel_netlink_close(); thread_destroy_master(master); master = thread_make_master(); free_global_data(global_data); free_interface_queue(); free_vrrp_buffer(); gratuitous_arp_close(); ndisc_close(); #ifdef _WITH_LVS_ if (vrrp_ipvs_needed()) { /* Clean ipvs related */ ipvs_stop(); } #endif /* Save previous conf data */ old_vrrp_data = vrrp_data; vrrp_data = NULL; /* Reload the conf */ mem_allocated = 0; vrrp_signal_init(); signal_set(SIGCHLD, thread_child_handler, master); start_vrrp(); /* free backup data */ free_vrrp_data(old_vrrp_data); UNSET_RELOAD; return 0; } /* VRRP Child respawning thread */ int vrrp_respawn_thread(thread_t * thread) { pid_t pid; /* Fetch thread args */ pid = THREAD_CHILD_PID(thread); /* Restart respawning thread */ if (thread->type == THREAD_CHILD_TIMEOUT) { thread_add_child(master, vrrp_respawn_thread, NULL, pid, RESPAWN_TIMER); return 0; } /* We catch a SIGCHLD, handle it */ if (!(debug & 64)) { log_message(LOG_ALERT, "VRRP child process(%d) died: Respawning", pid); start_vrrp_child(); } else { log_message(LOG_ALERT, "VRRP child process(%d) died: Exiting", pid); raise(SIGTERM); } return 0; } /* Register VRRP thread */ int start_vrrp_child(void) { #ifndef _DEBUG_ pid_t pid; int ret; /* Initialize child process */ pid = fork(); if (pid < 0) { log_message(LOG_INFO, "VRRP child process: fork error(%s)" , strerror(errno)); return -1; } else if (pid) { vrrp_child = pid; log_message(LOG_INFO, "Starting VRRP child process, pid=%d" , pid); /* Start respawning thread */ thread_add_child(master, vrrp_respawn_thread, NULL, pid, RESPAWN_TIMER); return 0; } /* Opening local VRRP syslog channel */ openlog(PROG_VRRP, LOG_PID | ((debug & 1) ? LOG_CONS : 0), (log_facility==LOG_DAEMON) ? LOG_LOCAL1 : log_facility); /* Child process part, write pidfile */ if (!pidfile_write(vrrp_pidfile, getpid())) { /* Fatal error */ log_message(LOG_INFO, "VRRP child process: cannot write pidfile"); exit(0); } /* Create the new master thread */ signal_handler_destroy(); thread_destroy_master(master); master = thread_make_master(); /* change to / dir */ ret = chdir("/"); if (ret < 0) { log_message(LOG_INFO, "VRRP child process: error chdir"); } /* Set mask */ umask(0); #endif /* If last process died during a reload, we can get there and we * don't want to loop again, because we're not reloading anymore. */ UNSET_RELOAD; /* Signal handling initialization */ vrrp_signal_init(); /* Start VRRP daemon */ start_vrrp(); /* Launch the scheduling I/O multiplexer */ launch_scheduler(); /* Finish VRRP daemon process */ stop_vrrp(); exit(0); } keepalived-1.2.13/keepalived/vrrp/vrrp_iproute.c0000644000175000017500000002136312256127641021544 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: NETLINK IPv4 routes manipulation. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ /* local include */ #include "vrrp_ipaddress.h" #include "vrrp_iproute.h" #include "vrrp_netlink.h" #include "vrrp_if.h" #include "vrrp_data.h" #include "logger.h" #include "memory.h" #include "utils.h" /* Utility functions */ static int add_addr2req(struct nlmsghdr *n, int maxlen, int type, ip_address_t *ip_address) { void *addr; int alen; if (!ip_address) return -1; addr = (IP_IS6(ip_address)) ? (void *) &ip_address->u.sin6_addr : (void *) &ip_address->u.sin.sin_addr; alen = (IP_IS6(ip_address)) ? sizeof(ip_address->u.sin6_addr) : sizeof(ip_address->u.sin.sin_addr); return addattr_l(n, maxlen, type, addr, alen); } static int add_addr2rta(struct rtattr *rta, int maxlen, int type, ip_address_t *ip_address) { void *addr; int alen; if (!ip_address) return -1; addr = (IP_IS6(ip_address)) ? (void *) &ip_address->u.sin6_addr : (void *) &ip_address->u.sin.sin_addr; alen = (IP_IS6(ip_address)) ? sizeof(ip_address->u.sin6_addr) : sizeof(ip_address->u.sin.sin_addr); return rta_addattr_l(rta, maxlen, type, addr, alen); } /* Add/Delete IP route to/from a specific interface */ int netlink_route(ip_route_t *iproute, int cmd) { int status = 1; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; char buf[1024]; struct rtattr *rta = (void*)buf; struct rtnexthop *rtnh; memset(&req, 0, sizeof (req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; req.n.nlmsg_type = cmd ? RTM_NEWROUTE : RTM_DELROUTE; req.r.rtm_family = IP_FAMILY(iproute->dst);; req.r.rtm_table = iproute->table ? iproute->table : RT_TABLE_MAIN; req.r.rtm_scope = RT_SCOPE_NOWHERE; if (cmd) { req.r.rtm_protocol = RTPROT_BOOT; req.r.rtm_scope = iproute->scope; req.r.rtm_type = RTN_UNICAST; } if (iproute->blackhole) req.r.rtm_type = RTN_BLACKHOLE; /* Set routing entry */ req.r.rtm_dst_len = iproute->dmask; add_addr2req(&req.n, sizeof(req), RTA_DST, iproute->dst); if ((!iproute->blackhole) && (!iproute->gw2)) add_addr2req(&req.n, sizeof(req), RTA_GATEWAY, iproute->gw); if (iproute->gw2) { rta->rta_type = RTA_MULTIPATH; rta->rta_len = RTA_LENGTH(0); rtnh = RTA_DATA(rta); #define MULTIPATH_ADD_GW(x) \ memset(rtnh, 0, sizeof(*rtnh)); \ rtnh->rtnh_len = sizeof(*rtnh); \ if (iproute->index) rtnh->rtnh_ifindex = iproute->index; \ rta->rta_len += rtnh->rtnh_len; \ add_addr2rta(rta, 1024, RTA_GATEWAY, x); \ rtnh->rtnh_len += sizeof(struct rtattr) + IP_SIZE(x); \ rtnh = RTNH_NEXT(rtnh); MULTIPATH_ADD_GW(iproute->gw); MULTIPATH_ADD_GW(iproute->gw2); addattr_l(&req.n, sizeof(req), RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta)); } if ((iproute->index) && (!iproute->gw2)) addattr32(&req.n, sizeof(req), RTA_OIF, iproute->index); if (iproute->src) add_addr2req(&req.n, sizeof(req), RTA_PREFSRC, iproute->src); if (iproute->metric) addattr32(&req.n, sizeof(req), RTA_PRIORITY, iproute->metric); if (netlink_talk(&nl_cmd, &req.n) < 0) status = -1; return status; } /* Add/Delete a list of IP routes */ void netlink_rtlist(list rt_list, int cmd) { ip_route_t *iproute; element e; /* No routes to add */ if (LIST_ISEMPTY(rt_list)) return; for (e = LIST_HEAD(rt_list); e; ELEMENT_NEXT(e)) { iproute = ELEMENT_DATA(e); if ((cmd && !iproute->set) || (!cmd && iproute->set)) { if (netlink_route(iproute, cmd) > 0) iproute->set = (cmd) ? 1 : 0; else iproute->set = 0; } } } /* Route dump/allocation */ void free_iproute(void *rt_data) { FREE(rt_data); } void dump_iproute(void *rt_data) { ip_route_t *route = rt_data; char *log_msg = MALLOC(1024); char *tmp = MALLOC(INET6_ADDRSTRLEN + 30); char *tmp_str; if (route->blackhole) { strncat(log_msg, "blackhole ", 30); } if (route->dst) { tmp_str = ipaddresstos(route->dst); snprintf(tmp, INET6_ADDRSTRLEN + 30, "%s/%d", tmp_str, route->dmask); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); FREE(tmp_str); } if (route->gw) { tmp_str = ipaddresstos(route->gw); snprintf(tmp, INET6_ADDRSTRLEN + 30, " gw %s", tmp_str); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); FREE(tmp_str); } if (route->gw2) { tmp_str = ipaddresstos(route->gw2); snprintf(tmp, INET6_ADDRSTRLEN + 30, " or gw %s", tmp_str); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); FREE(tmp_str); } if (route->src) { tmp_str = ipaddresstos(route->src); snprintf(tmp, INET6_ADDRSTRLEN + 30, " src %s", tmp_str); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); FREE(tmp_str); } if (route->index) { snprintf(tmp, INET6_ADDRSTRLEN + 30, " dev %s", IF_NAME(if_get_by_ifindex(route->index))); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); } if (route->table) { snprintf(tmp, INET6_ADDRSTRLEN + 30, " table %d", route->table); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); } if (route->scope) { snprintf(tmp, INET6_ADDRSTRLEN + 30, " scope %s", netlink_scope_n2a(route->scope)); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); } if (route->metric) { snprintf(tmp, INET6_ADDRSTRLEN + 30, " metric %d", route->metric); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); } log_message(LOG_INFO, " %s", log_msg); FREE(tmp); FREE(log_msg); } void alloc_route(list rt_list, vector_t *strvec) { ip_route_t *new; interface_t *ifp; char *str; int i = 0; new = (ip_route_t *) MALLOC(sizeof(ip_route_t)); /* FMT parse */ while (i < vector_size(strvec)) { str = vector_slot(strvec, i); /* cmd parsing */ if (!strcmp(str, "blackhole")) { new->blackhole = 1; new->dst = parse_ipaddress(NULL, vector_slot(strvec, ++i)); new->dmask = new->dst->ifa.ifa_prefixlen; } else if (!strcmp(str, "via") || !strcmp(str, "gw")) { new->gw = parse_ipaddress(NULL, vector_slot(strvec, ++i)); } else if (!strcmp(str, "or")) { new->gw2 = parse_ipaddress(NULL, vector_slot(strvec, ++i)); } else if (!strcmp(str, "src")) { new->src = parse_ipaddress(NULL, vector_slot(strvec, ++i)); } else if (!strcmp(str, "dev") || !strcmp(str, "oif")) { ifp = if_get_by_ifname(vector_slot(strvec, ++i)); if (!ifp) { log_message(LOG_INFO, "VRRP is trying to assign VROUTE to unknown " "%s interface !!! go out and fix your conf !!!", (char *)vector_slot(strvec, i)); FREE(new); return; } new->index = IF_INDEX(ifp); } else if (!strcmp(str, "table")) { new->table = atoi(vector_slot(strvec, ++i)); } else if (!strcmp(str, "metric")) { new->metric = atoi(vector_slot(strvec, ++i)); } else if (!strcmp(str, "scope")) { new->scope = netlink_scope_a2n(vector_slot(strvec, ++i)); } else { if (!strcmp(str, "to")) i++; new->dst = parse_ipaddress(NULL, vector_slot(strvec, i)); if (new->dst) { new->dmask = new->dst->ifa.ifa_prefixlen; } } i++; } list_add(rt_list, new); } /* Try to find a route in a list */ int route_exist(list l, ip_route_t *iproute) { ip_route_t *ipr; element e; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { ipr = ELEMENT_DATA(e); if (ROUTE_ISEQ(ipr, iproute)) { ipr->set = iproute->set; return 1; } } return 0; } /* Clear diff routes */ void clear_diff_routes(list l, list n) { ip_route_t *iproute; char *tmp_str; element e; /* No route in previous conf */ if (LIST_ISEMPTY(l)) return; /* All Static routes removed */ if (LIST_ISEMPTY(n)) { log_message(LOG_INFO, "Removing a VirtualRoute block"); netlink_rtlist(l, IPROUTE_DEL); return; } for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { iproute = ELEMENT_DATA(e); if (!route_exist(n, iproute) && iproute->set) { tmp_str = ipaddresstos(iproute->dst); log_message(LOG_INFO, "ip route %s/%d ... , no longer exist" , tmp_str, iproute->dmask); FREE(tmp_str); netlink_route(iproute, IPROUTE_DEL); } } } /* Diff conf handler */ void clear_diff_sroutes(void) { clear_diff_routes(old_vrrp_data->static_routes, vrrp_data->static_routes); } keepalived-1.2.13/keepalived/vrrp/vrrp_if.c0000644000175000017500000003616012334173466020457 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Interfaces manipulation. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ /* global include */ #include #include #include typedef uint64_t u64; typedef uint32_t u32; typedef uint16_t u16; typedef uint8_t u8; #include #include #include #include #include #include #include #ifdef use_linux_libc5 #include #include #endif #include #include #ifdef _KRNL_2_4_ #include #endif /* local include */ #include "scheduler.h" #include "global_data.h" #include "vrrp_data.h" #include "vrrp.h" #include "vrrp_if.h" #include "vrrp_netlink.h" #include "memory.h" #include "utils.h" #include "logger.h" /* Global vars */ static list if_queue; static struct ifreq ifr; /* Helper functions */ /* Return interface from interface index */ interface_t * if_get_by_ifindex(const int ifindex) { interface_t *ifp; element e; if (LIST_ISEMPTY(if_queue)) return NULL; for (e = LIST_HEAD(if_queue); e; ELEMENT_NEXT(e)) { ifp = ELEMENT_DATA(e); if (ifp->ifindex == ifindex) return ifp; } return NULL; } /* Return interface from VMAC base interface index */ interface_t * if_get_by_vmac_base_ifindex(const int ifindex) { interface_t *ifp; element e; if (LIST_ISEMPTY(if_queue) || !ifindex) return NULL; for (e = LIST_HEAD(if_queue); e; ELEMENT_NEXT(e)) { ifp = ELEMENT_DATA(e); if (ifp->vmac && ifp->base_ifindex == ifindex) return ifp; } return NULL; } interface_t * if_get_by_ifname(const char *ifname) { interface_t *ifp; element e; if (LIST_ISEMPTY(if_queue)) return NULL; for (e = LIST_HEAD(if_queue); e; ELEMENT_NEXT(e)) { ifp = ELEMENT_DATA(e); if (!strcmp(ifp->ifname, ifname)) return ifp; } return NULL; } /* MII Transceiver Registers poller functions */ static int if_mii_read(const int fd, const int phy_id, int location) { uint16_t *data = (uint16_t *) (&ifr.ifr_data); data[0] = phy_id; data[1] = location; if (ioctl(fd, SIOCGMIIREG, &ifr) < 0) { log_message(LOG_ERR, "SIOCGMIIREG on %s failed: %s", ifr.ifr_name, strerror(errno)); return -1; } return data[3]; } /* static void if_mii_dump(const uint16_t mii_regs[32], unsigned phy_id) { int mii_reg; printf(" MII PHY #%d transceiver registers:\n", phy_id); for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n ":"", mii_regs[mii_reg]); } */ static int if_mii_status(const int fd) { uint16_t *data = (uint16_t *) (&ifr.ifr_data); unsigned phy_id = data[0]; uint16_t mii_regs[32]; int mii_reg; uint16_t bmsr, new_bmsr; /* Reset MII registers */ memset(mii_regs, 0, sizeof (mii_regs)); for (mii_reg = 0; mii_reg < 32; mii_reg++) mii_regs[mii_reg] = if_mii_read(fd, phy_id, mii_reg); // if_mii_dump(mii_regs, phy_id); if (mii_regs[0] == 0xffff) { log_message(LOG_ERR, "No MII transceiver present for %s !!!", ifr.ifr_name); return -1; } bmsr = mii_regs[1]; /* * For Basic Mode Status Register (BMSR). * Sticky field (Link established & Jabber detected), we need to read * a second time the BMSR to get current status. */ new_bmsr = if_mii_read(fd, phy_id, 1); // printf(" \nBasic Mode Status Register 0x%4.4x ... 0x%4.4x\n", bmsr, new_bmsr); if (bmsr & 0x0004) return LINK_UP; else if (new_bmsr & 0x0004) return LINK_UP; else return LINK_DOWN; } int if_mii_probe(const char *ifname) { uint16_t *data = (uint16_t *) (&ifr.ifr_data); int phy_id; int fd = socket(AF_INET, SOCK_DGRAM, 0); int status = 0; if (fd < 0) return -1; memset(&ifr, 0, sizeof (struct ifreq)); strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); if (ioctl(fd, SIOCGMIIPHY, &ifr) < 0) { close(fd); return -1; } /* check if the driver reports BMSR using the MII interface, as we * will need this and we already know that some don't support it. */ phy_id = data[0]; /* save it in case it is overwritten */ data[1] = 1; if (ioctl(fd, SIOCGMIIREG, &ifr) < 0) { close(fd); return -1; } data[0] = phy_id; /* Dump the MII transceiver */ status = if_mii_status(fd); close(fd); return status; } static int if_ethtool_status(const int fd) { #ifdef ETHTOOL_GLINK struct ethtool_value edata; int err = 0; edata.cmd = ETHTOOL_GLINK; ifr.ifr_data = (caddr_t) & edata; err = ioctl(fd, SIOCETHTOOL, &ifr); if (err == 0) return (edata.data) ? 1 : 0; else #endif return -1; } int if_ethtool_probe(const char *ifname) { int fd = socket(AF_INET, SOCK_DGRAM, 0); int status = 0; if (fd < 0) return -1; memset(&ifr, 0, sizeof (struct ifreq)); strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); status = if_ethtool_status(fd); close(fd); return status; } void if_ioctl_flags(interface_t * ifp) { int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) return; memset(&ifr, 0, sizeof (struct ifreq)); strncpy(ifr.ifr_name, ifp->ifname, sizeof (ifr.ifr_name)); if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { close(fd); return; } ifp->flags = ifr.ifr_flags; close(fd); } /* Interfaces lookup */ static void free_if(void *data) { FREE(data); } void dump_if(void *data) { interface_t *ifp = data; char addr_str[41]; log_message(LOG_INFO, "------< NIC >------"); log_message(LOG_INFO, " Name = %s", ifp->ifname); log_message(LOG_INFO, " index = %d", ifp->ifindex); log_message(LOG_INFO, " IPv4 address = %s", inet_ntop2(ifp->sin_addr.s_addr)); inet_ntop(AF_INET6, &ifp->sin6_addr, addr_str, 41); log_message(LOG_INFO, " IPv6 address = %s", addr_str); /* FIXME: Harcoded for ethernet */ if (ifp->hw_type == ARPHRD_ETHER) log_message(LOG_INFO, " MAC = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", ifp->hw_addr[0], ifp->hw_addr[1], ifp->hw_addr[2] , ifp->hw_addr[3], ifp->hw_addr[4], ifp->hw_addr[5]); if (ifp->flags & IFF_UP) log_message(LOG_INFO, " is UP"); if (ifp->flags & IFF_RUNNING) log_message(LOG_INFO, " is RUNNING"); if (!(ifp->flags & IFF_UP) && !(ifp->flags & IFF_RUNNING)) log_message(LOG_INFO, " is DOWN"); log_message(LOG_INFO, " MTU = %d", ifp->mtu); switch (ifp->hw_type) { case ARPHRD_LOOPBACK: log_message(LOG_INFO, " HW Type = LOOPBACK"); break; case ARPHRD_ETHER: log_message(LOG_INFO, " HW Type = ETHERNET"); break; default: log_message(LOG_INFO, " HW Type = UNKNOWN"); break; } /* MII channel supported ? */ if (IF_MII_SUPPORTED(ifp)) log_message(LOG_INFO, " NIC support MII regs"); else if (IF_ETHTOOL_SUPPORTED(ifp)) log_message(LOG_INFO, " NIC support EHTTOOL GLINK interface"); else log_message(LOG_INFO, " Enabling NIC ioctl refresh polling"); } static void init_if_queue(void) { if_queue = alloc_list(free_if, dump_if); } void if_add_queue(interface_t * ifp) { list_add(if_queue, ifp); } static int if_linkbeat_refresh_thread(thread_t * thread) { interface_t *ifp = THREAD_ARG(thread); if (IF_MII_SUPPORTED(ifp)) ifp->linkbeat = (if_mii_probe(ifp->ifname)) ? 1 : 0; else if (IF_ETHTOOL_SUPPORTED(ifp)) ifp->linkbeat = (if_ethtool_probe(ifp->ifname)) ? 1 : 0; else ifp->linkbeat = 1; /* * update ifp->flags to get the new IFF_RUNNING status. * Some buggy drivers need this... */ if_ioctl_flags(ifp); /* Register next polling thread */ thread_add_timer(master, if_linkbeat_refresh_thread, ifp, POLLING_DELAY); return 0; } static void init_if_linkbeat(void) { interface_t *ifp; element e; int status; for (e = LIST_HEAD(if_queue); e; ELEMENT_NEXT(e)) { ifp = ELEMENT_DATA(e); ifp->lb_type = LB_IOCTL; status = if_mii_probe(ifp->ifname); if (status >= 0) { ifp->lb_type = LB_MII; ifp->linkbeat = (status) ? 1 : 0; } else { status = if_ethtool_probe(ifp->ifname); if (status >= 0) { ifp->lb_type = LB_ETHTOOL; ifp->linkbeat = (status) ? 1 : 0; } } /* Register new monitor thread */ thread_add_timer(master, if_linkbeat_refresh_thread, ifp, POLLING_DELAY); } } int if_linkbeat(const interface_t * ifp) { if (!global_data->linkbeat_use_polling) return 1; if (IF_MII_SUPPORTED(ifp) || IF_ETHTOOL_SUPPORTED(ifp)) return IF_LINKBEAT(ifp); return 1; } /* Interface queue helpers*/ void free_interface_queue(void) { if (!LIST_ISEMPTY(if_queue)) free_list(if_queue); if_queue = NULL; } void init_interface_queue(void) { init_if_queue(); // dump_list(if_queue); netlink_interface_lookup(); } void init_interface_linkbeat(void) { if (global_data->linkbeat_use_polling) { log_message(LOG_INFO, "Using MII-BMSR NIC polling thread..."); init_if_linkbeat(); } else { log_message(LOG_INFO, "Using LinkWatch kernel netlink reflector..."); } } int if_join_vrrp_group(sa_family_t family, int *sd, interface_t *ifp, int proto) { struct ip_mreqn imr; struct ipv6_mreq imr6; int ret = 0; if (*sd < 0) return -1; /* -> outbound processing option * join the multicast group. * binding the socket to the interface for outbound multicast * traffic. */ if (family == AF_INET) { memset(&imr, 0, sizeof(imr)); imr.imr_multiaddr = ((struct sockaddr_in *) &global_data->vrrp_mcast_group4)->sin_addr; imr.imr_address.s_addr = IF_ADDR(ifp); imr.imr_ifindex = IF_INDEX(ifp); /* -> Need to handle multicast convergance after takeover. * We retry until multicast is available on the interface. */ ret = setsockopt(*sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &imr, sizeof(struct ip_mreqn)); } else { memset(&imr6, 0, sizeof(imr6)); imr6.ipv6mr_multiaddr = ((struct sockaddr_in6 *) &global_data->vrrp_mcast_group6)->sin6_addr; imr6.ipv6mr_interface = IF_INDEX(ifp); ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *) &imr6, sizeof(struct ipv6_mreq)); } if (ret < 0) { log_message(LOG_INFO, "cant do IP%s_ADD_MEMBERSHIP errno=%s (%d)", (family == AF_INET) ? "" : "V6", strerror(errno), errno); close(*sd); *sd = -1; } return *sd; } int if_leave_vrrp_group(sa_family_t family, int sd, interface_t *ifp) { struct ip_mreq imr; struct ipv6_mreq imr6; int ret = 0; /* If fd is -1 then we add a membership trouble */ if (sd < 0 || !ifp) return -1; /* Leaving the VRRP multicast group */ if (family == AF_INET) { memset(&imr, 0, sizeof(imr)); imr.imr_multiaddr = ((struct sockaddr_in *) &global_data->vrrp_mcast_group4)->sin_addr; imr.imr_interface.s_addr = IF_ADDR(ifp); ret = setsockopt(sd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *) &imr, sizeof(struct ip_mreq)); } else { memset(&imr6, 0, sizeof(imr6)); imr6.ipv6mr_multiaddr = ((struct sockaddr_in6 *) &global_data->vrrp_mcast_group6)->sin6_addr; imr6.ipv6mr_interface = IF_INDEX(ifp); ret = setsockopt(sd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (char *) &imr6, sizeof(struct ipv6_mreq)); } if (ret < 0) { log_message(LOG_INFO, "cant do IP%s_DROP_MEMBERSHIP errno=%s (%d)", (family == AF_INET) ? "" : "V6", strerror(errno), errno); close(sd); return -1; } /* Finally close the desc */ close(sd); return 0; } int if_setsockopt_bindtodevice(int *sd, interface_t *ifp) { int ret; if (*sd < 0) return -1; /* -> inbound processing option * Specify the bound_dev_if. * why IP_ADD_MEMBERSHIP & IP_MULTICAST_IF doesnt set * sk->bound_dev_if themself ??? !!! * Needed for filter multicasted advert per interface. * * -- If you read this !!! and know the answer to the question * please feel free to answer me ! :) */ ret = setsockopt(*sd, SOL_SOCKET, SO_BINDTODEVICE, IF_NAME(ifp), strlen(IF_NAME(ifp)) + 1); if (ret < 0) { log_message(LOG_INFO, "cant bind to device %s. errno=%d. (try to run it as root)", IF_NAME(ifp), errno); close(*sd); *sd = -1; } return *sd; } int if_setsockopt_hdrincl(int *sd) { int ret; int on = 1; if (*sd < 0) return -1; /* Include IP header into RAW protocol packet */ ret = setsockopt(*sd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)); if (ret < 0) { log_message(LOG_INFO, "cant set HDRINCL IP option. errno=%d (%m)", errno); close(*sd); *sd = -1; } return *sd; } int if_setsockopt_mcast_loop(sa_family_t family, int *sd) { int ret; unsigned char loop = 0; int loopv6 = 0; if (*sd < 0) return -1; /* Include IP header into RAW protocol packet */ if (family == AF_INET) ret = setsockopt(*sd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); else ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loopv6, sizeof(loopv6)); if (ret < 0) { log_message(LOG_INFO, "cant set IP%s_MULTICAST_LOOP IP option. errno=%d (%m)", (family == AF_INET) ? "" : "V6", errno); close(*sd); *sd = -1; } return *sd; } int if_setsockopt_mcast_hops(sa_family_t family, int *sd) { int ret; int hops = 255; /* Not applicable for IPv4 */ if (*sd < 0 || family == AF_INET) return -1; /* Include IP header into RAW protocol packet */ ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops)); if (ret < 0) { log_message(LOG_INFO, "cant set IPV6_MULTICAST_HOPS IP option. errno=%d (%m)", errno); close(*sd); *sd = -1; } return *sd; } int if_setsockopt_mcast_if(sa_family_t family, int *sd, interface_t *ifp) { int ret; unsigned int ifindex; /* Not applicable for IPv4 */ if (*sd < 0 || family == AF_INET) return -1; /* Include IP header into RAW protocol packet */ ifindex = IF_INDEX(ifp); ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)); if (ret < 0) { log_message(LOG_INFO, "cant set IPV6_MULTICAST_IF IP option. errno=%d (%m)", errno); close(*sd); *sd = -1; } return *sd; } int if_setsockopt_priority(int *sd) { int ret; int priority = 6; if (*sd < 0) return -1; /* Set SO_PRIORITY for VRRP traffic */ ret = setsockopt(*sd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)); if (ret < 0) { log_message(LOG_INFO, "cant set SO_PRIORITY IP option. errno=%d (%m)", errno); close(*sd); *sd = -1; } return *sd; } int if_setsockopt_sndbuf(int *sd, int val) { int ret; if (*sd < 0) return -1; /* sndbuf option */ ret = setsockopt(*sd, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)); if (ret < 0) { log_message(LOG_INFO, "cant set SO_SNDBUF IP option. errno=%d (%m)", errno); close(*sd); *sd = -1; } return *sd; } int if_setsockopt_rcvbuf(int *sd, int val) { int ret; if (*sd < 0) return -1; /* rcvbuf option */ ret = setsockopt(*sd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)); if (ret < 0) { log_message(LOG_INFO, "cant set SO_RCVBUF IP option. errno=%d (%m)", errno); close(*sd); *sd = -1; } return *sd; } keepalived-1.2.13/keepalived/vrrp/Makefile.in0000644000175000017500000001030712256127641020701 0ustar acassenacassen# Makefile # # Keepalived OpenSource project. # # Copyright (C) 2001-2012 Alexandre Cassen, CC = @CC@ SNMP_FLAG = @SNMP_SUPPORT@ INCLUDES = -I../include -I../../lib CFLAGS = @CFLAGS@ @CPPFLAGS@ $(INCLUDES) \ -Wall -Wunused -Wstrict-prototypes DEFS = -D@KERN@ -D@IPVS_SUPPORT@ -D@IPVS_SYNCD@ -D@VRRP_VMAC@ -D@SNMP_SUPPORT@ @DFLAGS@ COMPILE = $(CC) $(CFLAGS) $(DEFS) OBJS = vrrp_daemon.o vrrp_data.o vrrp_parser.o \ vrrp.o vrrp_notify.o vrrp_scheduler.o vrrp_sync.o vrrp_index.o \ vrrp_netlink.o vrrp_arp.o vrrp_if.o vrrp_track.o vrrp_ipaddress.o \ vrrp_iproute.o vrrp_ipsecah.o vrrp_ndisc.o vrrp_vmac.o ifeq ($(SNMP_FLAG),_WITH_SNMP_) OBJS += vrrp_snmp.o endif HEADERS = $(OBJS:.o=.h) .c.o: $(COMPILE) -c $< all: $(OBJS) clean: rm -f *.a *.o *~ distclean: clean rm -f Makefile vrrp_daemon.o: vrrp_daemon.c ../include/vrrp_daemon.h ../include/vrrp_scheduler.h \ ../include/vrrp_if.h ../include/vrrp_arp.h ../include/vrrp_netlink.h ../include/vrrp_iproute.h \ ../include/vrrp_iproute.h ../include/vrrp_parser.h ../include/vrrp_data.h \ ../include/vrrp.h ../include/global_data.h ../include/pidfile.h ../include/daemon.h \ ../include/ipvswrapper.h ../../lib/list.h ../../lib/memory.h ../../lib/parser.h \ ../../lib/signals.h ../include/snmp.h ../include/vrrp_snmp.h vrrp_data.o: vrrp_data.c ../include/vrrp_data.h \ ../include/vrrp_sync.h ../include/vrrp_if.h ../include/vrrp_vmac.h ../include/vrrp_index.h \ ../include/vrrp.h ../../lib/memory.h ../../lib/utils.h ../../lib/notify.h vrrp_parser.o: vrrp_parser.c ../include/vrrp_parser.h \ ../include/vrrp_data.h ../include/vrrp_sync.h ../include/vrrp_index.h \ ../include/vrrp.h ../include/global_data.h ../include/global_parser.h \ ../../lib/parser.h ../../lib/memory.h vrrp.o: vrrp.c ../include/vrrp.h ../include/vrrp_scheduler.h \ ../include/vrrp_notify.h ../include/ipvswrapper.h ../../lib/memory.h \ ../../lib/list.h ../include/vrrp_data.h ../include/vrrp_sync.h ../include/vrrp_index.h \ ../include/vrrp_arp.h ../../lib/utils.h ../include/vrrp_vmac.h ../include/snmp.h \ ../include/vrrp_snmp.h vrrp_notify.o: vrrp_notify.c ../include/vrrp_notify.h ../../lib/memory.h \ ../../lib/notify.h vrrp_scheduler.o: vrrp_scheduler.c ../include/vrrp_scheduler.h \ ../include/vrrp_ipsecah.h ../include/vrrp_if.h ../include/vrrp_vmac.h ../include/vrrp.h \ ../include/vrrp_sync.h ../include/vrrp_notify.h ../include/ipvswrapper.h \ ../../lib/memory.h ../../lib/list.h ../include/vrrp_data.h ../include/vrrp_index.h \ ../include/smtp.h ../../lib/notify.h ../include/snmp.h ../include/vrrp_snmp.h vrrp_sync.o: vrrp_sync.c ../include/vrrp_sync.h ../include/vrrp_if.h \ ../include/vrrp_notify.h ../include/vrrp_data.h vrrp_index.o: vrrp_index.c ../include/vrrp_index.h ../include/vrrp.h \ ../include/vrrp_data.h ../../lib/memory.h vrrp_netlink.o: vrrp_netlink.c ../include/vrrp_netlink.h ../include/check_api.h \ ../include/vrrp_if.h ../../lib/memory.h ../../lib/scheduler.h \ ../../lib/utils.h vrrp_arp.o: vrrp_arp.c ../include/vrrp_arp.h vrrp_track.o: vrrp_track.c ../include/vrrp_track.h ../include/vrrp_if.h \ ../include/vrrp_data.h ../../lib/memory.h vrrp_if.o: vrrp_if.c ../include/vrrp_if.h ../include/vrrp_netlink.h \ ../../lib/scheduler.h ../include/vrrp_data.h ../../lib/memory.h \ ../../lib/utils.h vrrp_ipaddress.o: vrrp_ipaddress.c ../include/vrrp_ipaddress.h ../include/vrrp_netlink.h \ ../include/vrrp_if.h ../include/vrrp_data.h ../../lib/memory.h ../../lib/utils.h vrrp_iproute.o: vrrp_iproute.c ../include/vrrp_iproute.h ../include/vrrp_netlink.h \ ../include/vrrp_if.h ../include/vrrp_data.h ../../lib/memory.h ../../lib/utils.h vrrp_ipsecah.o: vrrp_ipsecah.c ../include/vrrp_ipsecah.h vrrp_ndisc.o: vrrp_ndisc.c ../include/vrrp_ndisc.h ../include/vrrp_ipaddress.h \ ../../lib/utils.h ../../lib/memory.h vrrp_vmac.o: vrrp_vmac.c ../include/vrrp_vmac.h ../include/vrrp_netlink.h \ ../include/vrrp_data.h ../../lib/logger.h ../../lib/memory.h ../../lib/utils.h vrrp_snmp.o: vrrp_snmp.c ../include/vrrp_snmp.h ../include/vrrp_track.h \ ../include/vrrp_data.h ../include/vrrp_ipaddress.h ../include/vrrp_iproute.h \ ../include/vrrp.h ../../lib/vector.h ../../lib/list.h ../include/snmp.h \ ../include/global_data.h ../../lib/logger.h keepalived-1.2.13/keepalived/vrrp/vrrp_notify.c0000664000175000017500000001225212211121152021342 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: VRRP state transition notification scripts handling. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ /* system include */ #include /* local include */ #include "vrrp_notify.h" #include "memory.h" #include "notify.h" #include "logger.h" static char * get_iscript(vrrp_t * vrrp, int state) { if (!vrrp->notify_exec) return NULL; if (state == VRRP_STATE_BACK) return vrrp->script_backup; if (state == VRRP_STATE_MAST) return vrrp->script_master; if (state == VRRP_STATE_FAULT) return vrrp->script_fault; return NULL; } static char * get_igscript(vrrp_t * vrrp) { return vrrp->script; } static char * get_gscript(vrrp_sgroup_t * vgroup, int state) { if (!vgroup->notify_exec) return NULL; if (state == VRRP_STATE_BACK) return vgroup->script_backup; if (state == VRRP_STATE_MAST) return vgroup->script_master; if (state == VRRP_STATE_FAULT) return vgroup->script_fault; return NULL; } static char * get_ggscript(vrrp_sgroup_t * vgroup) { return vgroup->script; } static char * notify_script_name(char *cmdline) { char *cp = cmdline; char *script; int str_len; if (!cmdline) return NULL; while (!isspace((int) *cp) && *cp != '\0') cp++; str_len = cp - cmdline; script = MALLOC(str_len + 1); memcpy(script, cmdline, str_len); *(script + str_len) = '\0'; return script; } static int script_open_litteral(char *script) { log_message(LOG_DEBUG, "Opening script file %s",script); FILE *fOut = fopen(script, "r");; if (!fOut) { log_message(LOG_INFO, "Can't open %s (errno %d %s)", script, errno, strerror(errno)); return 0; } fclose(fOut); return 1; } static int script_open(char *script) { char *name = notify_script_name(script); int ret = name ? script_open_litteral(name) : 0; if (name) FREE(name); return ret; } static int notify_script_exec(char* script, char *type, int state_num, char* name, int prio) { char *state = "{UNKNOWN}"; char *command_line = NULL; int size = 0; /* * Determine the length of the buffer that we'll need to generate the command * to run: * * "script" {GROUP|INSTANCE} "NAME" {MASTER|BACKUP|FAULT} PRIO * * Thus, the length of the buffer will be: * * ( strlen(script) + 3 ) + ( strlen(type) + 1 ) + ( strlen(name) + 1 ) + * ( strlen(state) + 2 ) + ( strlen(prio) + 1 ) + 1 * * Note that the prio will be indicated as zero for a group. * * Which is: * - The length of the script plus two enclosing quotes plus adjacent space * - The length of the type string plus the adjacent space * - The length of the name of the instance or group, plus two enclosing * quotes (just in case) * - The length of the state string plus the adjacent space * - The length of the priority value (3 digits) plus the adjacent * space * - The null-terminator * * Which results in: * * strlen(script) + strlen(type) + strlen(state) + strlen(name) + 12 */ switch (state_num) { case VRRP_STATE_MAST : state = "MASTER" ; break; case VRRP_STATE_BACK : state = "BACKUP" ; break; case VRRP_STATE_FAULT : state = "FAULT" ; break; } size = strlen(script) + strlen(type) + strlen(state) + strlen(name) + 12; command_line = MALLOC(size); if (!command_line) return 0; /* Launch the script */ snprintf(command_line, size, "\"%s\" %s \"%s\" %s %d", script, type, name, state, prio); notify_exec(command_line); FREE(command_line); return 1; } int notify_instance_exec(vrrp_t * vrrp, int state) { char *script = get_iscript(vrrp, state); char *gscript = get_igscript(vrrp); int ret = 0; /* Launch the notify_* script */ if (script && script_open(script)) { notify_exec(script); ret = 1; } /* Launch the generic notify script */ if (gscript && script_open_litteral(gscript)) { notify_script_exec(gscript, "INSTANCE", state, vrrp->iname, vrrp->effective_priority); ret = 1; } return ret; } int notify_group_exec(vrrp_sgroup_t * vgroup, int state) { char *script = get_gscript(vgroup, state); char *gscript = get_ggscript(vgroup); int ret = 0; /* Launch the notify_* script */ if (script && script_open(script)) { notify_exec(script); ret = 1; } /* Launch the generic notify script */ if (gscript && script_open_litteral(gscript)) { notify_script_exec(gscript, "GROUP", state, vgroup->gname, 0); ret = 1; } return ret; } keepalived-1.2.13/keepalived/vrrp/vrrp_sync.c0000664000175000017500000001670212211121152021012 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: VRRP synchronization framework. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "vrrp_sync.h" #include "vrrp_if.h" #include "vrrp_notify.h" #include "vrrp_data.h" #ifdef _WITH_SNMP_ #include "vrrp_snmp.h" #endif #include "logger.h" #include "smtp.h" /* Compute the new instance sands */ void vrrp_init_instance_sands(vrrp_t * vrrp) { set_time_now(); if (vrrp->state == VRRP_STATE_MAST || vrrp->state == VRRP_STATE_GOTO_MASTER || vrrp->state == VRRP_STATE_GOTO_FAULT || vrrp->wantstate == VRRP_STATE_GOTO_MASTER) { vrrp->sands.tv_sec = time_now.tv_sec + vrrp->adver_int / TIMER_HZ; vrrp->sands.tv_usec = time_now.tv_usec; return; } if (vrrp->state == VRRP_STATE_BACK || vrrp->state == VRRP_STATE_FAULT) vrrp->sands = timer_add_long(time_now, vrrp->ms_down_timer); } /* Instance name lookup */ vrrp_t * vrrp_get_instance(char *iname) { vrrp_t *vrrp; list l = vrrp_data->vrrp; element e; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); if (strcmp(vrrp->iname, iname) == 0) return vrrp; } return NULL; } /* Set instances group pointer */ void vrrp_sync_set_group(vrrp_sgroup_t *vgroup) { vrrp_t *vrrp; char *str; int i; for (i = 0; i < vector_size(vgroup->iname); i++) { str = vector_slot(vgroup->iname, i); vrrp = vrrp_get_instance(str); if (vrrp) { if (LIST_ISEMPTY(vgroup->index_list)) vgroup->index_list = alloc_list(NULL, NULL); list_add(vgroup->index_list, vrrp); vrrp->sync = vgroup; } } } /* All interface are UP in the same group */ int vrrp_sync_group_up(vrrp_sgroup_t * vgroup) { vrrp_t *vrrp; element e; list l = vgroup->index_list; int is_up = 0; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); if (VRRP_ISUP(vrrp)) is_up++; } if (is_up == LIST_SIZE(vgroup->index_list)) { log_message(LOG_INFO, "Kernel is reporting: Group(%s) UP" , GROUP_NAME(vgroup)); return 1; } return 0; } /* SMTP alert group notifier */ void vrrp_sync_smtp_notifier(vrrp_sgroup_t *vgroup) { if (vgroup->smtp_alert) { if (GROUP_STATE(vgroup) == VRRP_STATE_MAST) smtp_alert(NULL, NULL, vgroup, "Entering MASTER state", "=> All VRRP group instances are now in MASTER state <="); if (GROUP_STATE(vgroup) == VRRP_STATE_BACK) smtp_alert(NULL, NULL, vgroup, "Entering BACKUP state", "=> All VRRP group instances are now in BACKUP state <="); } } /* Leaving fault state */ int vrrp_sync_leave_fault(vrrp_t * vrrp) { vrrp_sgroup_t *vgroup = vrrp->sync; if (vrrp_sync_group_up(vgroup)) { log_message(LOG_INFO, "VRRP_Group(%s) Leaving FAULT state", GROUP_NAME(vgroup)); return 1; } return 0; } /* Check transition to master state */ int vrrp_sync_goto_master(vrrp_t * vrrp) { vrrp_t *isync; vrrp_sgroup_t *vgroup = vrrp->sync; list l = vgroup->index_list; element e; if (GROUP_STATE(vgroup) == VRRP_STATE_MAST) return 1; if (GROUP_STATE(vgroup) == VRRP_STATE_GOTO_MASTER) return 1; /* Only sync to master if everyone wants to * i.e. prefer backup state to avoid thrashing */ for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { isync = ELEMENT_DATA(e); if (isync != vrrp && (isync->wantstate != VRRP_STATE_GOTO_MASTER && isync->wantstate != VRRP_STATE_MAST)) { return 0; } } return 1; } void vrrp_sync_master_election(vrrp_t * vrrp) { vrrp_t *isync; vrrp_sgroup_t *vgroup = vrrp->sync; list l = vgroup->index_list; element e; if (vrrp->wantstate != VRRP_STATE_GOTO_MASTER) return; if (GROUP_STATE(vgroup) == VRRP_STATE_FAULT) return; log_message(LOG_INFO, "VRRP_Group(%s) Transition to MASTER state", GROUP_NAME(vgroup)); /* Perform sync index */ for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { isync = ELEMENT_DATA(e); if (isync != vrrp && isync->wantstate != VRRP_STATE_GOTO_MASTER) { /* Force a new protocol master election */ isync->wantstate = VRRP_STATE_GOTO_MASTER; log_message(LOG_INFO, "VRRP_Instance(%s) forcing a new MASTER election", isync->iname); vrrp_send_adv(isync, isync->effective_priority); } } } void vrrp_sync_backup(vrrp_t * vrrp) { vrrp_t *isync; vrrp_sgroup_t *vgroup = vrrp->sync; list l = vgroup->index_list; element e; if (GROUP_STATE(vgroup) == VRRP_STATE_BACK) return; log_message(LOG_INFO, "VRRP_Group(%s) Syncing instances to BACKUP state", GROUP_NAME(vgroup)); /* Perform sync index */ for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { isync = ELEMENT_DATA(e); if (isync != vrrp && isync->state != VRRP_STATE_BACK) { isync->wantstate = VRRP_STATE_BACK; vrrp_state_leave_master(isync); vrrp_init_instance_sands(isync); } } vgroup->state = VRRP_STATE_BACK; vrrp_sync_smtp_notifier(vgroup); notify_group_exec(vgroup, VRRP_STATE_BACK); #ifdef _WITH_SNMP_ vrrp_snmp_group_trap(vgroup); #endif } void vrrp_sync_master(vrrp_t * vrrp) { vrrp_t *isync; vrrp_sgroup_t *vgroup = vrrp->sync; list l = vgroup->index_list; element e; if (GROUP_STATE(vgroup) == VRRP_STATE_MAST) return; if (!vrrp_sync_goto_master(vrrp)) return; log_message(LOG_INFO, "VRRP_Group(%s) Syncing instances to MASTER state", GROUP_NAME(vgroup)); /* Perform sync index */ for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { isync = ELEMENT_DATA(e); /* Send the higher priority advert on all synced instances */ if (isync != vrrp && isync->state != VRRP_STATE_MAST) { isync->wantstate = VRRP_STATE_MAST; vrrp_state_goto_master(isync); vrrp_init_instance_sands(isync); } } vgroup->state = VRRP_STATE_MAST; vrrp_sync_smtp_notifier(vgroup); notify_group_exec(vgroup, VRRP_STATE_MAST); #ifdef _WITH_SNMP_ vrrp_snmp_group_trap(vgroup); #endif } void vrrp_sync_fault(vrrp_t * vrrp) { vrrp_t *isync; vrrp_sgroup_t *vgroup = vrrp->sync; list l = vgroup->index_list; element e; if (GROUP_STATE(vgroup) == VRRP_STATE_FAULT) return; log_message(LOG_INFO, "VRRP_Group(%s) Syncing instances to FAULT state", GROUP_NAME(vgroup)); /* Perform sync index */ for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { isync = ELEMENT_DATA(e); /* * We force sync instance to backup mode. * This reduce instance takeover to less than ms_down_timer. * => by default ms_down_timer is set to 3secs. * => Takeover will be less than 3secs ! */ if (isync != vrrp && isync->state != VRRP_STATE_FAULT) { if (isync->state == VRRP_STATE_MAST) isync->wantstate = VRRP_STATE_GOTO_FAULT; if (isync->state == VRRP_STATE_BACK) isync->state = VRRP_STATE_FAULT; } } vgroup->state = VRRP_STATE_FAULT; notify_group_exec(vgroup, VRRP_STATE_FAULT); #ifdef _WITH_SNMP_ vrrp_snmp_group_trap(vgroup); #endif } keepalived-1.2.13/keepalived/vrrp/vrrp_arp.c0000644000175000017500000000661712334352414020637 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: ARP primitives. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ /* system includes */ #include #include /* local includes */ #include "logger.h" #include "memory.h" #include "utils.h" #include "vrrp_arp.h" /* global vars */ char *garp_buffer; int garp_fd; /* Send the gratuitous ARP message */ static int send_arp(ip_address_t *ipaddress) { struct sockaddr_ll sll; int len; /* Build the dst device */ memset(&sll, 0, sizeof(sll)); sll.sll_family = AF_PACKET; memcpy(sll.sll_addr, IF_HWADDR(ipaddress->ifp), ETH_ALEN); sll.sll_halen = ETHERNET_HW_LEN; sll.sll_ifindex = IF_INDEX(ipaddress->ifp); /* Send packet */ len = sendto(garp_fd, garp_buffer, sizeof(arphdr_t) + ETHER_HDR_LEN , 0, (struct sockaddr *)&sll, sizeof(sll)); if (len < 0) log_message(LOG_INFO, "Error sending gratuitous ARP on %s for %s", IF_NAME(ipaddress->ifp), inet_ntop2(ipaddress->u.sin.sin_addr.s_addr)); return len; } /* Build a gratuitous ARP message over a specific interface */ int send_gratuitous_arp(ip_address_t *ipaddress) { struct ether_header *eth = (struct ether_header *) garp_buffer; arphdr_t *arph = (arphdr_t *) (garp_buffer + ETHER_HDR_LEN); char *hwaddr = (char *) IF_HWADDR(ipaddress->ifp); int len; /* Ethernet header */ memset(eth->ether_dhost, 0xFF, ETH_ALEN); memcpy(eth->ether_shost, hwaddr, ETH_ALEN); eth->ether_type = htons(ETHERTYPE_ARP); /* ARP payload */ arph->ar_hrd = htons(ARPHRD_ETHER); arph->ar_pro = htons(ETHERTYPE_IP); arph->ar_hln = ETHERNET_HW_LEN; arph->ar_pln = IPPROTO_ADDR_LEN; arph->ar_op = htons(ARPOP_REQUEST); memcpy(arph->__ar_sha, hwaddr, ETH_ALEN); memcpy(arph->__ar_sip, &ipaddress->u.sin.sin_addr.s_addr, sizeof(struct in_addr)); memset(arph->__ar_tha, 0xFF, ETH_ALEN); memcpy(arph->__ar_tip, &ipaddress->u.sin.sin_addr.s_addr, sizeof(struct in_addr)); /* Send the ARP message */ len = send_arp(ipaddress); /* Cleanup room for next round */ memset(garp_buffer, 0, sizeof(arphdr_t) + ETHER_HDR_LEN); return len; } /* * Gratuitous ARP init/close */ void gratuitous_arp_init(void) { /* Initalize shared buffer */ garp_buffer = (char *)MALLOC(sizeof(arphdr_t) + ETHER_HDR_LEN); /* Create the socket descriptor */ garp_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_RARP)); if (garp_fd > 0) log_message(LOG_INFO, "Registering gratuitous ARP shared channel"); else log_message(LOG_INFO, "Error while registering gratuitous ARP shared channel"); } void gratuitous_arp_close(void) { FREE(garp_buffer); close(garp_fd); } keepalived-1.2.13/keepalived/vrrp/vrrp_ipsecah.c0000664000175000017500000000561212211121152021450 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: IPSEC AH implementation according to RFC 2402. Processing * authentication data encryption using HMAC MD5 according to * RFCs 2085 & 2104. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "vrrp_ipsecah.h" #include /* hmac_md5 computation according to the RFCs 2085 & 2104 */ void hmac_md5(unsigned char *buffer, int buffer_len, unsigned char *key, int key_len, unsigned char *digest) { MD5_CTX context; unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */ unsigned char k_opad[65]; /* outer padding - key XORd with opad */ unsigned char tk[16]; int i; /* Initialize data */ memset(k_ipad, 0, sizeof (k_ipad)); memset(k_opad, 0, sizeof (k_opad)); memset(tk, 0, sizeof (tk)); /* If the key is longer than 64 bytes => set it to key=MD5(key) */ if (key_len > 64) { MD5_CTX tctx; /* Compute the MD5 digest */ MD5_Init(&tctx); MD5_Update(&tctx, key, key_len); MD5_Final(tk, &tctx); key = tk; key_len = 16; } /* The global HMAC_MD5 algo looks like (rfc2085.2.2) : MD5(K XOR opad, MD5(K XOR ipad, buffer)) K : an n byte key ipad : byte 0x36 repeated 64 times opad : byte 0x5c repeated 64 times buffer : buffer being protected */ memset(k_ipad, 0, sizeof (k_ipad)); memset(k_opad, 0, sizeof (k_opad)); memcpy(k_ipad, key, key_len); memcpy(k_opad, key, key_len); /* XOR key with ipad and opad values */ for (i = 0; i < 64; i++) { k_ipad[i] ^= 0x36; k_opad[i] ^= 0x5c; } /* Compute inner MD5 */ MD5_Init(&context); /* Init context for 1st pass */ MD5_Update(&context, k_ipad, 64); /* start with inner pad */ MD5_Update(&context, buffer, buffer_len); /* next with buffer datagram */ MD5_Final(digest, &context); /* Finish 1st pass */ /* Compute outer MD5 */ MD5_Init(&context); /* Init context for 2nd pass */ MD5_Update(&context, k_opad, 64); /* start with inner pad */ MD5_Update(&context, digest, 16); /* next result of 1st pass */ MD5_Final(digest, &context); /* Finish 2nd pass */ } keepalived-1.2.13/keepalived/vrrp/vrrp_index.c0000644000175000017500000000600512271465302021154 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: VRRP instance index table. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ /* local include */ #include "vrrp_index.h" #include "vrrp_data.h" #include "vrrp.h" #include "memory.h" #include "list.h" /* VRID hash table */ void alloc_vrrp_bucket(vrrp_t *vrrp) { list_add(&vrrp_data->vrrp_index[vrrp->vrid], vrrp); } vrrp_t * vrrp_index_lookup(const int vrid, const int fd) { vrrp_t *vrrp; element e; list l = &vrrp_data->vrrp_index[vrid]; /* return if list is empty */ if (LIST_ISEMPTY(l)) return NULL; /* * If list size's is 1 then no collisions. So * Test and return the singleton. */ if (LIST_SIZE(l) == 1) { vrrp = ELEMENT_DATA(LIST_HEAD(l)); return (vrrp->fd_in == fd) ? vrrp : NULL; } /* * List collision on the vrid bucket. The same * vrid is used on a different interface. We perform * a fd lookup as collisions solver. */ for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); if (vrrp->fd_in == fd) return vrrp; } /* No match */ return NULL; } /* FD hash table */ void alloc_vrrp_fd_bucket(vrrp_t *vrrp) { /* We use a mod key plus 1 */ list_add(&vrrp_data->vrrp_index_fd[vrrp->fd_in%1024 + 1], vrrp); } void remove_vrrp_fd_bucket(vrrp_t *vrrp) { list l = &vrrp_data->vrrp_index_fd[vrrp->fd_in%1024 + 1]; list_del(l, vrrp); } void set_vrrp_fd_bucket(int old_fd, vrrp_t *vrrp) { vrrp_t *vrrp_ptr; element e; element next; list l = &vrrp_data->vrrp_index_fd[old_fd%1024 + 1]; /* Release old stalled entries */ for (e = LIST_HEAD(l); e; e = next) { next = e->next; vrrp_ptr = ELEMENT_DATA(e); if (vrrp_ptr->fd_in == old_fd) { if (e->prev) e->prev->next = e->next; else l->head = e->next; if (e->next) e->next->prev = e->prev; else l->tail = e->prev; l->count--; FREE(e); } } if (LIST_ISEMPTY(l)) l->head = l->tail = NULL; /* Hash refreshed entries */ l = vrrp_data->vrrp; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vrrp_ptr = ELEMENT_DATA(e); if (vrrp_ptr->fd_in == old_fd) { /* Update new hash */ vrrp_ptr->fd_in = vrrp->fd_in; vrrp_ptr->fd_out = vrrp->fd_out; alloc_vrrp_fd_bucket(vrrp_ptr); } } } keepalived-1.2.13/keepalived/vrrp/vrrp.c0000644000175000017500000011311612334072037017766 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: VRRP implementation of VRRPv2 as specified in rfc2338. * VRRP is a protocol which elect a master server on a LAN. If the * master fails, a backup server takes over. * The original implementation has been made by jerome etienne. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ /* local include */ #include #include #include "vrrp_arp.h" #include "vrrp_ndisc.h" #include "vrrp_scheduler.h" #include "vrrp_notify.h" #include "ipvswrapper.h" #include "vrrp.h" #include "vrrp_data.h" #include "vrrp_sync.h" #include "vrrp_index.h" #include "vrrp_vmac.h" #ifdef _WITH_SNMP_ #include "vrrp_snmp.h" #endif #include "memory.h" #include "list.h" #include "logger.h" #include "main.h" #include "utils.h" #include "notify.h" /* add/remove Virtual IP addresses */ static int vrrp_handle_ipaddress(vrrp_t * vrrp, int cmd, int type) { if (debug & 32) log_message(LOG_INFO, "VRRP_Instance(%s) %s protocol %s", vrrp->iname, (cmd == IPADDRESS_ADD) ? "setting" : "removing", (type == VRRP_VIP_TYPE) ? "VIPs." : "E-VIPs."); netlink_iplist((type == VRRP_VIP_TYPE) ? vrrp->vip : vrrp->evip, cmd); return 1; } /* add/remove Virtual routes */ static int vrrp_handle_iproutes(vrrp_t * vrrp, int cmd) { if (debug & 32) log_message(LOG_INFO, "VRRP_Instance(%s) %s protocol Virtual Routes", vrrp->iname, (cmd == IPROUTE_ADD) ? "setting" : "removing"); netlink_rtlist(vrrp->vroutes, cmd); return 1; } /* IP header length */ static int vrrp_iphdr_len(vrrp_t * vrrp) { return sizeof(struct iphdr); } /* IPSEC AH header length */ int vrrp_ipsecah_len(void) { return sizeof(ipsec_ah_t); } /* VRRP header length */ static int vrrp_hd_len(vrrp_t * vrrp) { int len = sizeof(vrrphdr_t); if (vrrp->family == AF_INET) len += VRRP_AUTH_LEN + ((!LIST_ISEMPTY(vrrp->vip)) ? LIST_SIZE(vrrp->vip) * sizeof (uint32_t) : 0); return len; } /* VRRP header pointer from buffer */ vrrphdr_t * vrrp_get_header(sa_family_t family, char *buf, int *proto, uint32_t *saddr) { struct iphdr *iph; vrrphdr_t *hd = NULL; if (family == AF_INET) { iph = (struct iphdr *) buf; *saddr = iph->saddr; /* Fill the VRRP header */ switch (iph->protocol) { case IPPROTO_IPSEC_AH: *proto = IPPROTO_IPSEC_AH; hd = (vrrphdr_t *) ((char *) iph + (iph->ihl << 2) + vrrp_ipsecah_len()); break; case IPPROTO_VRRP: *proto = IPPROTO_VRRP; hd = (vrrphdr_t *) ((char *) iph + (iph->ihl << 2)); break; } } else if (family == AF_INET6) { *proto = IPPROTO_VRRP; *saddr = 0; hd = (vrrphdr_t *) buf; } return hd; } /* * IPSEC AH incoming packet check. * return 0 for a valid pkt, != 0 otherwise. */ static int vrrp_in_chk_ipsecah(vrrp_t * vrrp, char *buffer) { struct iphdr *ip = (struct iphdr *) (buffer); ipsec_ah_t *ah = (ipsec_ah_t *) ((char *) ip + (ip->ihl << 2)); unsigned char *digest; uint32_t backup_auth_data[3]; /* first verify that the SPI value is equal to src IP */ if (ah->spi != ip->saddr) { log_message(LOG_INFO, "IPSEC AH : invalid IPSEC SPI value. %d and expect %d", ip->saddr, ah->spi); return 1; } /* * then proceed with the sequence number to prevent against replay attack. * For inbound processing, we increment seq_number counter to audit * sender counter. */ vrrp->ipsecah_counter->seq_number++; if (ntohl(ah->seq_number) >= vrrp->ipsecah_counter->seq_number || vrrp->sync) { vrrp->ipsecah_counter->seq_number = ntohl(ah->seq_number); } else { log_message(LOG_INFO, "VRRP_Instance(%s) IPSEC-AH : sequence number %d" " already proceeded. Packet dropped. Local(%d)", vrrp->iname , ntohl(ah->seq_number), vrrp->ipsecah_counter->seq_number); return 1; } /* * then compute a ICV to compare with the one present in AH pkt. * alloc a temp memory space to stock the ip mutable fields */ digest = (unsigned char *) MALLOC(16); /*MD5_DIGEST_LENGTH */ /* zero the ip mutable fields */ ip->tos = 0; ip->frag_off = 0; ip->check = 0; memcpy(backup_auth_data, ah->auth_data, sizeof (ah->auth_data)); memset(ah->auth_data, 0, sizeof (ah->auth_data)); /* Compute the ICV */ hmac_md5((unsigned char *) buffer, vrrp_iphdr_len(vrrp) + vrrp_ipsecah_len() + vrrp_hd_len(vrrp) , vrrp->auth_data, sizeof (vrrp->auth_data) , digest); if (memcmp(backup_auth_data, digest, HMAC_MD5_TRUNC) != 0) { log_message(LOG_INFO, "VRRP_Instance(%s) IPSEC-AH : invalid" " IPSEC HMAC-MD5 value. Due to fields mutation" " or bad password !", vrrp->iname); return 1; } FREE(digest); return 0; } /* check if ipaddr is present in VIP buffer */ static int vrrp_in_chk_vips(vrrp_t * vrrp, ip_address_t *ipaddress, unsigned char *buffer) { int i; uint32_t ipbuf; /* Just skip IPv6 address, when we are using a mixed v4/v6 vips * set inside se same VRRP instance. */ if (IP_IS6(ipaddress)) return 1; for (i = 0; i < LIST_SIZE(vrrp->vip); i++) { bcopy(buffer + i * sizeof (uint32_t), &ipbuf, sizeof (uint32_t)); if (ipaddress->u.sin.sin_addr.s_addr == ipbuf) return 1; } return 0; } /* * VRRP incoming packet check. * return 0 if the pkt is valid, != 0 otherwise. */ static int vrrp_in_chk(vrrp_t * vrrp, char *buffer) { struct iphdr *ip; int ihl, vrrphdr_len; ipsec_ah_t *ah; vrrphdr_t *hd; unsigned char *vips; ip_address_t *ipaddress; element e; /* IPv4 related */ if (vrrp->family == AF_INET) { ip = (struct iphdr *) (buffer); ihl = ip->ihl << 2; if (vrrp->auth_type == VRRP_AUTH_AH) { ah = (ipsec_ah_t *) (buffer + ihl); hd = (vrrphdr_t *) ((char *) ah + vrrp_ipsecah_len()); } else { hd = (vrrphdr_t *) (buffer + ihl); } /* pointer to vrrp vips pkt zone */ vips = (unsigned char *) ((char *) hd + sizeof(vrrphdr_t)); /* MUST verify that the IP TTL is 255 */ if (LIST_ISEMPTY(vrrp->unicast_peer) && ip->ttl != VRRP_IP_TTL) { log_message(LOG_INFO, "invalid ttl. %d and expect %d", ip->ttl, VRRP_IP_TTL); return VRRP_PACKET_KO; } /* * MUST verify that the received packet length is greater than or * equal to the VRRP header */ if ((ntohs(ip->tot_len) - ihl) <= sizeof(vrrphdr_t)) { log_message(LOG_INFO, "ip payload too short. %d and expect at least %d", ntohs(ip->tot_len) - ihl, sizeof(vrrphdr_t)); return VRRP_PACKET_KO; } if (!LIST_ISEMPTY(vrrp->vip)) { /* * MAY verify that the IP address(es) associated with the * VRID are valid */ if (hd->naddr != LIST_SIZE(vrrp->vip)) { log_message(LOG_INFO, "receive an invalid ip number count associated with VRID!"); return VRRP_PACKET_KO; } for (e = LIST_HEAD(vrrp->vip); e; ELEMENT_NEXT(e)) { ipaddress = ELEMENT_DATA(e); if (!vrrp_in_chk_vips(vrrp, ipaddress, vips)) { log_message(LOG_INFO, "ip address associated with VRID" " not present in received packet : %s", inet_ntop2(ipaddress->u.sin.sin_addr.s_addr)); log_message(LOG_INFO, "one or more VIP associated with" " VRID mismatch actual MASTER advert"); return VRRP_PACKET_KO; } } } /* check the authentication if it is a passwd */ if (hd->auth_type == VRRP_AUTH_PASS) { char *pw = (char *) ip + ntohs(ip->tot_len) - sizeof (vrrp->auth_data); if (memcmp(pw, vrrp->auth_data, sizeof(vrrp->auth_data)) != 0) { log_message(LOG_INFO, "receive an invalid passwd!"); return VRRP_PACKET_KO; } } /* check the authenicaion if it is ipsec ah */ if (hd->auth_type == VRRP_AUTH_AH) return (vrrp_in_chk_ipsecah(vrrp, buffer)); /* Set expected vrrp packet lenght */ vrrphdr_len = sizeof(vrrphdr_t) + VRRP_AUTH_LEN + hd->naddr * sizeof(uint32_t); } else if (vrrp->family == AF_INET6) { /* IPv6 related */ hd = (vrrphdr_t *) buffer; vrrphdr_len = sizeof(vrrphdr_t); } else { return VRRP_PACKET_KO; } /* MUST verify the VRRP version */ if ((hd->vers_type >> 4) != VRRP_VERSION) { log_message(LOG_INFO, "invalid version. %d and expect %d", (hd->vers_type >> 4), VRRP_VERSION); return VRRP_PACKET_KO; } /* MUST verify the VRRP checksum */ if (in_csum((u_short *) hd, vrrphdr_len, 0)) { log_message(LOG_INFO, "Invalid vrrp checksum"); return VRRP_PACKET_KO; } /* * MUST perform authentication specified by Auth Type * check the authentication type */ if (vrrp->auth_type != hd->auth_type) { log_message(LOG_INFO, "receive a %d auth, expecting %d!", hd->auth_type, vrrp->auth_type); return VRRP_PACKET_KO; } /* MUST verify that the VRID is valid on the receiving interface_t */ if (vrrp->vrid != hd->vrid) { log_message(LOG_INFO, "received VRID mismatch. Received %d, Expected %d", hd->vrid, vrrp->vrid); return VRRP_PACKET_DROP; } if (LIST_ISEMPTY(vrrp->vip) && hd->naddr > 0) { log_message(LOG_INFO, "receive an invalid ip number count associated with VRID!"); return VRRP_PACKET_KO; } /* * MUST verify that the Adver Interval in the packet is the same as * the locally configured for this virtual router */ if (vrrp->adver_int / TIMER_HZ != hd->adver_int) { log_message(LOG_INFO, "advertissement interval mismatch mine=%d rcved=%d", vrrp->adver_int, hd->adver_int); /* to prevent concurent VRID running => multiple master in 1 VRID */ return VRRP_PACKET_DROP; } return VRRP_PACKET_OK; } /* build IP header */ static void vrrp_build_ip4(vrrp_t * vrrp, char *buffer, int buflen, uint32_t dst) { struct iphdr *ip = (struct iphdr *) (buffer); ip->ihl = 5; ip->version = 4; /* set tos to internet network control */ ip->tos = 0xc0; ip->tot_len = ip->ihl * 4 + vrrp_hd_len(vrrp); ip->tot_len = htons(ip->tot_len); ip->id = htons(++vrrp->ip_id); /* kernel will fill in ID if left to 0, so we overflow to 1 */ if (vrrp->ip_id == 65535) vrrp->ip_id = 1; ip->frag_off = 0; ip->ttl = VRRP_IP_TTL; /* fill protocol type --rfc2402.2 */ ip->protocol = (vrrp->auth_type == VRRP_AUTH_AH) ? IPPROTO_IPSEC_AH : IPPROTO_VRRP; ip->saddr = VRRP_PKT_SADDR(vrrp); ip->daddr = dst; /* checksum must be done last */ ip->check = in_csum((u_short *) ip, ip->ihl * 4, 0); } /* build IPSEC AH header */ static void vrrp_build_ipsecah(vrrp_t * vrrp, char *buffer, int buflen) { ICV_mutable_fields *ip_mutable_fields; unsigned char *digest; struct iphdr *ip = (struct iphdr *) (buffer); ipsec_ah_t *ah = (ipsec_ah_t *) (buffer + sizeof (struct iphdr)); /* alloc a temp memory space to stock the ip mutable fields */ ip_mutable_fields = (ICV_mutable_fields *) MALLOC(sizeof (ICV_mutable_fields)); /* fill in next header filed --rfc2402.2.1 */ ah->next_header = IPPROTO_VRRP; /* update IP header total length value */ ip->tot_len = ip->ihl * 4 + vrrp_ipsecah_len() + vrrp_hd_len(vrrp); ip->tot_len = htons(ip->tot_len); /* update ip checksum */ ip->check = 0; ip->check = in_csum((u_short *) ip, ip->ihl * 4, 0); /* backup the ip mutable fields */ ip_mutable_fields->tos = ip->tos; ip_mutable_fields->frag_off = ip->frag_off; ip_mutable_fields->check = ip->check; /* zero the ip mutable fields */ ip->tos = 0; ip->frag_off = 0; ip->check = 0; /* fill in the Payload len field */ ah->payload_len = IPSEC_AH_PLEN; /* The SPI value is filled with the ip header source address. SPI uniquely identify the Security Association (SA). This value is chosen by the recipient itself when setting up the SA. In a multicast environment, this becomes unfeasible. If left to the sender, the choice of the SPI value should be done so by the sender that it cannot possibly conflict with SPI values chosen by other entities sending IPSEC traffic to any of the receivers. To overpass this problem, the rule I have chosen to implement here is that the SPI value chosen by the sender is based on unique information such as its IP address. -- INTERNET draft : */ ah->spi = ip->saddr; /* Processing sequence number. Cycled assumed if 0xFFFFFFFD reached. So the MASTER state is free for another srv. Here can result a flapping MASTER state owner when max seq_number value reached. => Much work needed here. In the current implementation if counter has cycled, we stop sending adverts and become BACKUP. If all the master are down we reset the counter for becoming MASTER. */ if (vrrp->ipsecah_counter->seq_number > 0xFFFFFFFD) { vrrp->ipsecah_counter->cycle = 1; } else { vrrp->ipsecah_counter->seq_number++; } ah->seq_number = htonl(vrrp->ipsecah_counter->seq_number); /* Compute the ICV & trunc the digest to 96bits => No padding needed. -- rfc2402.3.3.3.1.1.1 & rfc2401.5 */ digest = (unsigned char *) MALLOC(16); /*MD5_DIGEST_LENGTH */ hmac_md5((unsigned char *) buffer, buflen, vrrp->auth_data, sizeof (vrrp->auth_data) , digest); memcpy(ah->auth_data, digest, HMAC_MD5_TRUNC); /* Restore the ip mutable fields */ ip->tos = ip_mutable_fields->tos; ip->frag_off = ip_mutable_fields->frag_off; ip->check = ip_mutable_fields->check; FREE(ip_mutable_fields); FREE(digest); } /* build VRRP header */ static int vrrp_build_vrrp(vrrp_t * vrrp, int prio, char *buffer) { int i = 0; vrrphdr_t *hd = (vrrphdr_t *) buffer; uint32_t *iparr; element e; ip_address_t *ip_addr; /* Family independant */ hd->vers_type = (VRRP_VERSION << 4) | VRRP_PKT_ADVERT; hd->vrid = vrrp->vrid; hd->priority = prio; hd->naddr = (!LIST_ISEMPTY(vrrp->vip)) ? LIST_SIZE(vrrp->vip) : 0; hd->auth_type = vrrp->auth_type; hd->adver_int = vrrp->adver_int / TIMER_HZ; /* Family specific */ if (vrrp->family == AF_INET) { /* copy the ip addresses */ iparr = (uint32_t *) ((char *) hd + sizeof (*hd)); if (!LIST_ISEMPTY(vrrp->vip)) { for (e = LIST_HEAD(vrrp->vip); e; ELEMENT_NEXT(e)) { ip_addr = ELEMENT_DATA(e); if (IP_IS6(ip_addr)) continue; else iparr[i++] = ip_addr->u.sin.sin_addr.s_addr; } } /* copy the passwd if the authentication is VRRP_AH_PASS */ if (vrrp->auth_type == VRRP_AUTH_PASS) { int vip_count = (!LIST_ISEMPTY(vrrp->vip)) ? LIST_SIZE(vrrp->vip) : 0; char *pw = (char *) hd + sizeof (*hd) + vip_count * 4; memcpy(pw, vrrp->auth_data, sizeof (vrrp->auth_data)); } } /* finaly compute vrrp checksum */ hd->chksum = 0; hd->chksum = in_csum((u_short *) hd, vrrp_hd_len(vrrp), 0); return 0; } /* build VRRP packet */ static void vrrp_build_pkt(vrrp_t * vrrp, int prio, struct sockaddr_storage *addr) { char *bufptr; uint32_t dst; int len; /* save reference values */ bufptr = VRRP_SEND_BUFFER(vrrp); len = VRRP_SEND_BUFFER_SIZE(vrrp); if (vrrp->family == AF_INET) { /* build the ip header */ dst = (addr) ? inet_sockaddrip4(addr) : ((struct sockaddr_in *) &global_data->vrrp_mcast_group4)->sin_addr.s_addr; vrrp_build_ip4(vrrp, bufptr, len, dst); /* build the vrrp header */ vrrp->send_buffer += vrrp_iphdr_len(vrrp); if (vrrp->auth_type == VRRP_AUTH_AH) vrrp->send_buffer += vrrp_ipsecah_len(); vrrp->send_buffer_size -= vrrp_iphdr_len(vrrp); if (vrrp->auth_type == VRRP_AUTH_AH) vrrp->send_buffer_size -= vrrp_ipsecah_len(); vrrp_build_vrrp(vrrp, prio, vrrp->send_buffer); /* build the IPSEC AH header */ if (vrrp->auth_type == VRRP_AUTH_AH) { vrrp->send_buffer_size += vrrp_iphdr_len(vrrp) + vrrp_ipsecah_len(); vrrp_build_ipsecah(vrrp, bufptr, VRRP_SEND_BUFFER_SIZE(vrrp)); } } else if (vrrp->family == AF_INET6) { vrrp_build_vrrp(vrrp, prio, VRRP_SEND_BUFFER(vrrp)); } /* restore reference values */ vrrp->send_buffer = bufptr; vrrp->send_buffer_size = len; } /* send VRRP packet */ static int vrrp_send_pkt(vrrp_t * vrrp, struct sockaddr_storage *addr) { struct sockaddr_storage *src = &vrrp->saddr; struct sockaddr_in6 dst6; struct in6_pktinfo *pkt; struct sockaddr_in dst4; struct msghdr msg; struct cmsghdr *cmsg; struct iovec iov; char cbuf[256]; /* Build the message data */ memset(&msg, 0, sizeof(msg)); msg.msg_iov = &iov; msg.msg_iovlen = 1; iov.iov_base = VRRP_SEND_BUFFER(vrrp); iov.iov_len = VRRP_SEND_BUFFER_SIZE(vrrp); /* Unicast sending path */ if (addr && addr->ss_family == AF_INET) { msg.msg_name = (struct sockaddr_in *) addr; msg.msg_namelen = sizeof(struct sockaddr_in); } else if (addr && addr->ss_family == AF_INET6) { msg.msg_name = (struct sockaddr_in6 *) addr; msg.msg_namelen = sizeof(struct sockaddr_in6); if (src->ss_family == AF_INET6) { msg.msg_control = cbuf; msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_PKTINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); pkt = (struct in6_pktinfo *) CMSG_DATA(cmsg); memset(pkt, 0, sizeof(struct in6_pktinfo)); pkt->ipi6_addr = ((struct sockaddr_in6 *) src)->sin6_addr; } } else if (vrrp->family == AF_INET) { /* Multicast sending path */ memset(&dst4, 0, sizeof(dst4)); dst4.sin_family = AF_INET; dst4.sin_addr = ((struct sockaddr_in *) &global_data->vrrp_mcast_group4)->sin_addr; msg.msg_name = &dst4; msg.msg_namelen = sizeof(dst4); } else if (vrrp->family == AF_INET6) { memset(&dst6, 0, sizeof(dst6)); dst6.sin6_family = AF_INET6; dst6.sin6_addr = ((struct sockaddr_in6 *) &global_data->vrrp_mcast_group6)->sin6_addr; msg.msg_name = &dst6; msg.msg_namelen = sizeof(dst6); } /* Send the packet */ return sendmsg(vrrp->fd_out, &msg, (addr) ? 0 : MSG_DONTROUTE); } /* Allocate the sending buffer */ static void vrrp_alloc_send_buffer(vrrp_t * vrrp) { vrrp->send_buffer_size = vrrp_hd_len(vrrp); if (vrrp->family == AF_INET) { vrrp->send_buffer_size = vrrp_iphdr_len(vrrp) + vrrp_hd_len(vrrp); if (vrrp->auth_type == VRRP_AUTH_AH) vrrp->send_buffer_size += vrrp_ipsecah_len(); } vrrp->send_buffer = MALLOC(VRRP_SEND_BUFFER_SIZE(vrrp)); } /* send VRRP advertissement */ int vrrp_send_adv(vrrp_t * vrrp, int prio) { struct sockaddr_storage *addr; list l = vrrp->unicast_peer; element e; int ret; /* alloc send buffer */ if (!vrrp->send_buffer) vrrp_alloc_send_buffer(vrrp); else memset(vrrp->send_buffer, 0, VRRP_SEND_BUFFER_SIZE(vrrp)); /* build the packet */ if (!LIST_ISEMPTY(l)) { for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { addr = ELEMENT_DATA(e); vrrp_build_pkt(vrrp, prio, addr); ret = vrrp_send_pkt(vrrp, addr); if (ret < 0) { log_message(LOG_INFO, "VRRP_Instance(%s) Cant sent advert to %s (%m)" , vrrp->iname, inet_sockaddrtos(addr)); } } } else { vrrp_build_pkt(vrrp, prio, NULL); vrrp_send_pkt(vrrp, NULL); } /* send it */ return 0; } /* Received packet processing */ int vrrp_check_packet(vrrp_t * vrrp, char *buf, int buflen) { int ret; if (buflen > 0) { ret = vrrp_in_chk(vrrp, buf); if (ret == VRRP_PACKET_DROP) { log_message(LOG_INFO, "Sync instance needed on %s !!!", IF_NAME(vrrp->ifp)); } if (ret == VRRP_PACKET_KO) log_message(LOG_INFO, "bogus VRRP packet received on %s !!!", IF_NAME(vrrp->ifp)); return ret; } return VRRP_PACKET_NULL; } /* Gratuitous ARP on each VIP */ static void vrrp_send_update(vrrp_t * vrrp, ip_address_t * ipaddress, int idx) { char *msg; char addr_str[41]; if (!IP_IS6(ipaddress)) { msg = "gratuitous ARPs"; inet_ntop(AF_INET, &ipaddress->u.sin.sin_addr, addr_str, 41); send_gratuitous_arp(ipaddress); } else { msg = "Unsolicited Neighbour Adverts"; inet_ntop(AF_INET6, &ipaddress->u.sin6_addr, addr_str, 41); ndisc_send_unsolicited_na(ipaddress); } if (0 == idx && debug & 32) { log_message(LOG_INFO, "VRRP_Instance(%s) Sending %s on %s for %s", vrrp->iname, msg, IF_NAME(ipaddress->ifp), addr_str); } } void vrrp_send_link_update(vrrp_t * vrrp) { int j; ip_address_t *ipaddress; element e; /* Only send gratuitous ARP if VIP are set */ if (!VRRP_VIP_ISSET(vrrp)) return; /* send gratuitous arp for each virtual ip */ for (j = 0; j < 5; j++) { if (!LIST_ISEMPTY(vrrp->vip)) { for (e = LIST_HEAD(vrrp->vip); e; ELEMENT_NEXT(e)) { ipaddress = ELEMENT_DATA(e); vrrp_send_update(vrrp, ipaddress, j); } } if (!LIST_ISEMPTY(vrrp->evip)) { for (e = LIST_HEAD(vrrp->evip); e; ELEMENT_NEXT(e)) { ipaddress = ELEMENT_DATA(e); vrrp_send_update(vrrp, ipaddress, j); } } } } /* becoming master */ void vrrp_state_become_master(vrrp_t * vrrp) { /* add the ip addresses */ if (!LIST_ISEMPTY(vrrp->vip)) vrrp_handle_ipaddress(vrrp, IPADDRESS_ADD, VRRP_VIP_TYPE); if (!LIST_ISEMPTY(vrrp->evip)) vrrp_handle_ipaddress(vrrp, IPADDRESS_ADD, VRRP_EVIP_TYPE); vrrp->vipset = 1; /* add virtual routes */ if (!LIST_ISEMPTY(vrrp->vroutes)) vrrp_handle_iproutes(vrrp, IPROUTE_ADD); /* remotes neighbour update */ vrrp_send_link_update(vrrp); /* set refresh timer */ if (vrrp->garp_refresh) { vrrp->garp_refresh_timer = timer_add_long(time_now, vrrp->garp_refresh); } /* Check if notify is needed */ notify_instance_exec(vrrp, VRRP_STATE_MAST); #ifdef _WITH_SNMP_ vrrp_snmp_instance_trap(vrrp); #endif #ifdef _HAVE_IPVS_SYNCD_ /* Check if sync daemon handling is needed */ if (vrrp->lvs_syncd_if) ipvs_syncd_master(vrrp->lvs_syncd_if, vrrp->vrid); #endif } void vrrp_state_goto_master(vrrp_t * vrrp) { /* * Send an advertisement. To force a new master * election. */ if (vrrp->sync && !vrrp_sync_goto_master(vrrp)) { /* * Set quick sync flag to enable faster transition, i.e. check * again in the next interval instead of waiting three. */ vrrp->quick_sync = 1; return; } vrrp_send_adv(vrrp, vrrp->effective_priority); vrrp->state = VRRP_STATE_MAST; log_message(LOG_INFO, "VRRP_Instance(%s) Transition to MASTER STATE" , vrrp->iname); } /* leaving master state */ void vrrp_restore_interface(vrrp_t * vrrp, int advF) { /* if we stop vrrp, warn the other routers to speed up the recovery */ if (advF) { syslog(LOG_INFO, "VRRP_Instance(%s) sending 0 priority", vrrp->iname); vrrp_send_adv(vrrp, VRRP_PRIO_STOP); } /* remove virtual routes */ if (!LIST_ISEMPTY(vrrp->vroutes)) vrrp_handle_iproutes(vrrp, IPROUTE_DEL); /* * Remove the ip addresses. * * If started with "--dont-release-vrrp" (debug & 8) then try to remove * addresses even if we didn't add them during this run. */ if (debug & 8 || VRRP_VIP_ISSET(vrrp)) { if (!LIST_ISEMPTY(vrrp->vip)) vrrp_handle_ipaddress(vrrp, IPADDRESS_DEL, VRRP_VIP_TYPE); if (!LIST_ISEMPTY(vrrp->evip)) vrrp_handle_ipaddress(vrrp, IPADDRESS_DEL, VRRP_EVIP_TYPE); vrrp->vipset = 0; } } void vrrp_state_leave_master(vrrp_t * vrrp) { if (VRRP_VIP_ISSET(vrrp)) { #ifdef _HAVE_IPVS_SYNCD_ /* Check if sync daemon handling is needed */ if (vrrp->lvs_syncd_if) ipvs_syncd_backup(vrrp->lvs_syncd_if, vrrp->vrid); #endif } /* set the new vrrp state */ switch (vrrp->wantstate) { case VRRP_STATE_BACK: log_message(LOG_INFO, "VRRP_Instance(%s) Entering BACKUP STATE", vrrp->iname); vrrp_restore_interface(vrrp, 0); vrrp->state = vrrp->wantstate; notify_instance_exec(vrrp, VRRP_STATE_BACK); #ifdef _WITH_SNMP_ vrrp_snmp_instance_trap(vrrp); #endif break; case VRRP_STATE_GOTO_FAULT: log_message(LOG_INFO, "VRRP_Instance(%s) Entering FAULT STATE", vrrp->iname); vrrp_restore_interface(vrrp, 0); vrrp->state = VRRP_STATE_FAULT; notify_instance_exec(vrrp, VRRP_STATE_FAULT); vrrp_send_adv(vrrp, VRRP_PRIO_STOP); #ifdef _WITH_SNMP_ vrrp_snmp_instance_trap(vrrp); #endif break; } /* Set the down timer */ vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp); } /* BACKUP state processing */ void vrrp_state_backup(vrrp_t * vrrp, char *buf, int buflen) { vrrphdr_t *hd; uint32_t saddr; int ret = 0, proto; /* Process the incoming packet */ hd = vrrp_get_header(vrrp->family, buf, &proto, &saddr); ret = vrrp_check_packet(vrrp, buf, buflen); if (ret == VRRP_PACKET_KO || ret == VRRP_PACKET_NULL) { log_message(LOG_INFO, "VRRP_Instance(%s) ignoring received advertisment..." , vrrp->iname); vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp); } else if (hd->priority == 0) { vrrp->ms_down_timer = VRRP_TIMER_SKEW(vrrp); } else if (vrrp->nopreempt || hd->priority >= vrrp->effective_priority || timer_cmp(vrrp->preempt_time, timer_now()) > 0) { vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp); } else if (hd->priority < vrrp->effective_priority) { log_message(LOG_INFO, "VRRP_Instance(%s) forcing a new MASTER election" , vrrp->iname); vrrp->wantstate = VRRP_STATE_GOTO_MASTER; vrrp_send_adv(vrrp, vrrp->effective_priority); } } /* MASTER state processing */ int vrrp_state_master_tx(vrrp_t * vrrp, const int prio) { int ret = 0; if (!VRRP_VIP_ISSET(vrrp)) { log_message(LOG_INFO, "VRRP_Instance(%s) Entering MASTER STATE" , vrrp->iname); vrrp_state_become_master(vrrp); ret = 1; } else if (vrrp->garp_refresh && timer_cmp(time_now, vrrp->garp_refresh_timer) > 0) { vrrp_send_link_update(vrrp); vrrp->garp_refresh_timer = timer_add_long(time_now, vrrp->garp_refresh); } vrrp_send_adv(vrrp, (prio == VRRP_PRIO_OWNER) ? VRRP_PRIO_OWNER : vrrp->effective_priority); return ret; } int vrrp_state_master_rx(vrrp_t * vrrp, char *buf, int buflen) { vrrphdr_t *hd = NULL; int ret = 0, proto = 0; uint32_t saddr = 0; ipsec_ah_t *ah; /* return on link failure */ if (vrrp->wantstate == VRRP_STATE_GOTO_FAULT) { vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp); vrrp->state = VRRP_STATE_FAULT; notify_instance_exec(vrrp, VRRP_STATE_FAULT); return 1; } /* Process the incoming packet */ hd = vrrp_get_header(vrrp->family, buf, &proto, &saddr); ret = vrrp_check_packet(vrrp, buf, buflen); if (ret == VRRP_PACKET_KO || ret == VRRP_PACKET_NULL || ret == VRRP_PACKET_DROP) { log_message(LOG_INFO, "VRRP_Instance(%s) Dropping received VRRP packet...", vrrp->iname); return 0; } else if (hd->priority < vrrp->effective_priority) { /* We receive a lower prio adv we just refresh remote ARP cache */ log_message(LOG_INFO, "VRRP_Instance(%s) Received lower prio advert" ", forcing new election", vrrp->iname); if (proto == IPPROTO_IPSEC_AH) { ah = (ipsec_ah_t *) (buf + sizeof(struct iphdr)); log_message(LOG_INFO, "VRRP_Instance(%s) IPSEC-AH : Syncing seq_num" " - Increment seq" , vrrp->iname); vrrp->ipsecah_counter->seq_number = ntohl(ah->seq_number) + 1; vrrp->ipsecah_counter->cycle = 0; } vrrp_send_adv(vrrp, vrrp->effective_priority); vrrp_send_link_update(vrrp); return 0; } else if (hd->priority == 0) { vrrp_send_adv(vrrp, vrrp->effective_priority); return 0; } else if (vrrp->family == AF_INET) { if (hd->priority > vrrp->effective_priority || (hd->priority == vrrp->effective_priority && ntohl(saddr) > ntohl(VRRP_PKT_SADDR(vrrp)))) { /* We send a last advert here in order to refresh remote MASTER * coming up to force link update at MASTER side. */ vrrp_send_adv(vrrp, vrrp->effective_priority); log_message(LOG_INFO, "VRRP_Instance(%s) Received higher prio advert" , vrrp->iname); if (proto == IPPROTO_IPSEC_AH) { ah = (ipsec_ah_t *) (buf + sizeof(struct iphdr)); log_message(LOG_INFO, "VRRP_Instance(%s) IPSEC-AH : Syncing seq_num" " - Decrement seq" , vrrp->iname); vrrp->ipsecah_counter->seq_number = ntohl(ah->seq_number) - 1; vrrp->ipsecah_counter->cycle = 0; } vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp); vrrp->wantstate = VRRP_STATE_BACK; vrrp->state = VRRP_STATE_BACK; return 1; } } else if (vrrp->family == AF_INET6) { /* FIXME: compare v6 saddr to link local when prio are equal !!! */ if (hd->priority > vrrp->effective_priority) { /* We send a last advert here in order to refresh remote MASTER * coming up to force link update at MASTER side. */ vrrp_send_adv(vrrp, vrrp->effective_priority); log_message(LOG_INFO, "VRRP_Instance(%s) Received higher prio advert" , vrrp->iname); vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp); vrrp->wantstate = VRRP_STATE_BACK; vrrp->state = VRRP_STATE_BACK; return 1; } } return 0; } int vrrp_state_fault_rx(vrrp_t * vrrp, char *buf, int buflen) { vrrphdr_t *hd; uint32_t saddr; int ret = 0, proto; /* Process the incoming packet */ hd = vrrp_get_header(vrrp->family, buf, &proto, &saddr); ret = vrrp_check_packet(vrrp, buf, buflen); if (ret == VRRP_PACKET_KO || ret == VRRP_PACKET_NULL || ret == VRRP_PACKET_DROP) { log_message(LOG_INFO, "VRRP_Instance(%s) Dropping received VRRP packet..." , vrrp->iname); return 0; } else if (vrrp->effective_priority > hd->priority || hd->priority == VRRP_PRIO_OWNER) { if (!vrrp->nopreempt) return 1; } return 0; } /* check for minimum configuration requirements */ static int chk_min_cfg(vrrp_t * vrrp) { if (vrrp->vrid == 0) { log_message(LOG_INFO, "VRRP_Instance(%s) the virtual id must be set!", vrrp->iname); return 0; } if (!vrrp->ifp) { log_message(LOG_INFO, "VRRP_Instance(%s) Unknown interface !", vrrp->iname); return 0; } return 1; } /* open a VRRP sending socket */ int open_vrrp_send_socket(sa_family_t family, int proto, int idx, int unicast) { interface_t *ifp; int fd = -1; /* Retreive interface_t */ ifp = if_get_by_ifindex(idx); /* Create and init socket descriptor */ fd = socket(family, SOCK_RAW, proto); if (fd < 0) { log_message(LOG_INFO, "cant open raw socket. errno=%d", errno); return -1; } if (family == AF_INET) { /* Set v4 related */ if_setsockopt_hdrincl(&fd); if_setsockopt_bindtodevice(&fd, ifp); if (!unicast) if_setsockopt_mcast_loop(family, &fd); if_setsockopt_priority(&fd); if (fd < 0) return -1; } else if (family == AF_INET6) { /* Set v6 related */ if (!unicast) { if_setsockopt_mcast_hops(family, &fd); if_setsockopt_mcast_if(family, &fd, ifp); if_setsockopt_mcast_loop(family, &fd); } if_setsockopt_priority(&fd); if (fd < 0) return -1; } else { log_message(LOG_INFO, "cant open raw socket. unknow family=%d" , family); close(fd); return -1; } return fd; } /* open a VRRP socket and join the multicast group. */ int open_vrrp_socket(sa_family_t family, int proto, int idx, int unicast) { interface_t *ifp; int fd = -1; /* Retreive interface_t */ ifp = if_get_by_ifindex(idx); /* open the socket */ fd = socket(family, SOCK_RAW, proto); if (fd < 0) { int err = errno; log_message(LOG_INFO, "cant open raw socket. errno=%d", err); return -1; } /* Join the VRRP MCAST group */ if (!unicast) if_join_vrrp_group(family, &fd, ifp, proto); if (fd < 0) return -1; if (family == AF_INET) { /* Bind inbound stream */ if_setsockopt_bindtodevice(&fd, ifp); } return fd; } void close_vrrp_socket(vrrp_t * vrrp) { if (LIST_ISEMPTY(vrrp->unicast_peer)) { if_leave_vrrp_group(vrrp->family, vrrp->fd_in, vrrp->ifp); } else { close(vrrp->fd_in); } close(vrrp->fd_out); } int new_vrrp_socket(vrrp_t * vrrp) { int old_fd = vrrp->fd_in; int proto, ifindex, unicast; /* close the desc & open a new one */ close_vrrp_socket(vrrp); remove_vrrp_fd_bucket(vrrp); proto = (vrrp->auth_type == VRRP_AUTH_AH) ? IPPROTO_IPSEC_AH : IPPROTO_VRRP; ifindex = (vrrp->vmac_flags & VRRP_VMAC_FL_XMITBASE) ? IF_BASE_INDEX(vrrp->ifp) : IF_INDEX(vrrp->ifp); unicast = !LIST_ISEMPTY(vrrp->unicast_peer); vrrp->fd_in = open_vrrp_socket(vrrp->family, proto, ifindex, unicast); vrrp->fd_out = open_vrrp_send_socket(vrrp->family, proto, ifindex, unicast); alloc_vrrp_fd_bucket(vrrp); /* Sync the other desc */ set_vrrp_fd_bucket(old_fd, vrrp); return vrrp->fd_in; } /* handle terminate state */ void shutdown_vrrp_instances(void) { list l = vrrp_data->vrrp; element e; vrrp_t *vrrp; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); /* Remove VIPs/VROUTEs */ if (vrrp->state == VRRP_STATE_MAST) vrrp_restore_interface(vrrp, 1); /* Remove VMAC */ if (vrrp->vmac_flags & VRRP_VMAC_FL_SET) netlink_link_del_vmac(vrrp); /* Run stop script */ if (vrrp->script_stop) notify_exec(vrrp->script_stop); #ifdef _HAVE_IPVS_SYNCD_ /* * Stop stalled syncd. IPVS syncd state is the * same as VRRP instance one. We need here to * stop stalled syncd thread according to last * VRRP instance state. */ if (vrrp->lvs_syncd_if) ipvs_syncd_cmd(IPVS_STOPDAEMON, NULL, (vrrp->state == VRRP_STATE_MAST) ? IPVS_MASTER: IPVS_BACKUP, vrrp->vrid); #endif } } /* complete vrrp structure */ static int vrrp_complete_instance(vrrp_t * vrrp) { vrrp->state = VRRP_STATE_INIT; if (!vrrp->adver_int) vrrp->adver_int = VRRP_ADVER_DFL * TIMER_HZ; if (!vrrp->effective_priority) vrrp->effective_priority = VRRP_PRIO_DFL; return (chk_min_cfg(vrrp)); } int vrrp_complete_init(void) { list l; element e; vrrp_t *vrrp; vrrp_sgroup_t *sgroup; /* Complete VRRP instance initialization */ l = vrrp_data->vrrp; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); if (!vrrp_complete_instance(vrrp)) return 0; } /* Build synchronization group index */ l = vrrp_data->vrrp_sync_group; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { sgroup = ELEMENT_DATA(e); vrrp_sync_set_group(sgroup); } return 1; } int vrrp_ipvs_needed(void) { vrrp_t *vrrp; element e; if (!vrrp_data) return 0; for (e = LIST_HEAD(vrrp_data->vrrp); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); if (vrrp->lvs_syncd_if) { return 1; } } return 0; } /* Try to find a VRRP instance */ static vrrp_t * vrrp_exist(vrrp_t * old_vrrp) { element e; list l = vrrp_data->vrrp; vrrp_t *vrrp; if (LIST_ISEMPTY(l)) return NULL; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); if (!strcmp(vrrp->iname, old_vrrp->iname)) return vrrp; } return NULL; } /* Clear VIP|EVIP not present into the new data */ static void clear_diff_vrrp_vip(vrrp_t * old_vrrp, int type) { vrrp_t *vrrp = vrrp_exist(old_vrrp); list l = (type == VRRP_VIP_TYPE) ? old_vrrp->vip : old_vrrp->evip; list n = (type == VRRP_VIP_TYPE) ? vrrp->vip : vrrp->evip; clear_diff_address(l, n); } /* Clear virtual routes not present in the new data */ static void clear_diff_vrrp_vroutes(vrrp_t * old_vrrp) { vrrp_t *vrrp = vrrp_exist(old_vrrp); clear_diff_routes(old_vrrp->vroutes, vrrp->vroutes); } /* Keep the state from before reload */ static void reset_vrrp_state(vrrp_t * old_vrrp) { /* Keep VRRP state, ipsec AH seq_number */ vrrp_t *vrrp = vrrp_exist(old_vrrp); vrrp->state = old_vrrp->state; vrrp->init_state = old_vrrp->state; vrrp->wantstate = old_vrrp->state; if (!old_vrrp->sync) vrrp->effective_priority = old_vrrp->effective_priority; memcpy(vrrp->ipsecah_counter, old_vrrp->ipsecah_counter, sizeof(seq_counter_t)); #ifdef _HAVE_IPVS_SYNCD_ if (old_vrrp->lvs_syncd_if) ipvs_syncd_cmd(IPVS_STOPDAEMON, NULL, (old_vrrp->state == VRRP_STATE_MAST) ? IPVS_MASTER: IPVS_BACKUP, old_vrrp->vrid); if (vrrp->lvs_syncd_if) ipvs_syncd_cmd(IPVS_STARTDAEMON, NULL, (vrrp->state == VRRP_STATE_MAST) ? IPVS_MASTER: IPVS_BACKUP, vrrp->vrid); #endif /* Remember if we had vips up and add new ones if needed */ vrrp->vipset = old_vrrp->vipset; if (vrrp->vipset) { if (!LIST_ISEMPTY(vrrp->vip)) vrrp_handle_ipaddress(vrrp, IPADDRESS_ADD, VRRP_VIP_TYPE); if (!LIST_ISEMPTY(vrrp->evip)) vrrp_handle_ipaddress(vrrp, IPADDRESS_ADD, VRRP_EVIP_TYPE); if (!LIST_ISEMPTY(vrrp->vroutes)) vrrp_handle_iproutes(vrrp, IPROUTE_ADD); } } /* Diff when reloading configuration */ void clear_diff_vrrp(void) { element e; list l = old_vrrp_data->vrrp; vrrp_t *vrrp; if (LIST_ISEMPTY(l)) return; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); vrrp_t *new_vrrp; /* * Try to find this vrrp into the new conf data * reloaded. */ new_vrrp = vrrp_exist(vrrp); if (!new_vrrp) { vrrp_restore_interface(vrrp, 1); /* Remove VMAC if one was created */ if (vrrp->vmac_flags & VRRP_VMAC_FL_SET) netlink_link_del_vmac(vrrp); } else { /* * If this vrrp instance exist in new * data, then perform a VIP|EVIP diff. */ clear_diff_vrrp_vip(vrrp, VRRP_VIP_TYPE); clear_diff_vrrp_vip(vrrp, VRRP_EVIP_TYPE); /* virtual routes diff */ clear_diff_vrrp_vroutes(vrrp); /* * Remove VMAC if it existed in old vrrp instance, * but not the new one. */ if (vrrp->vmac_flags & VRRP_VMAC_FL_SET && !(new_vrrp->vmac_flags & VRRP_VMAC_FL_SET)) { netlink_link_del_vmac(vrrp); } /* reset the state */ reset_vrrp_state(vrrp); } } } /* Set script status to a sensible value on reload */ void clear_diff_script(void) { element e; list l = old_vrrp_data->vrrp_script; vrrp_script_t *vscript, *nvscript; if (LIST_ISEMPTY(l)) return; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vscript = ELEMENT_DATA(e); if (vscript->result >= vscript->rise) { nvscript = find_script_by_name(vscript->sname); if (nvscript) { log_message(LOG_INFO, "VRRP_Script(%s) considered successful on reload", nvscript->sname); nvscript->result = VRRP_SCRIPT_STATUS_INIT_GOOD; } } } } keepalived-1.2.13/keepalived/vrrp/vrrp_data.c0000644000175000017500000003504212334144643020763 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Dynamic data structure definition. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "vrrp_data.h" #include "vrrp_index.h" #include "vrrp_sync.h" #include "vrrp_if.h" #include "vrrp_vmac.h" #include "vrrp.h" #include "memory.h" #include "utils.h" #include "logger.h" /* global vars */ vrrp_data_t *vrrp_data = NULL; vrrp_data_t *old_vrrp_data = NULL; char *vrrp_buffer; /* Static addresses facility function */ void alloc_saddress(vector_t *strvec) { if (LIST_ISEMPTY(vrrp_data->static_addresses)) vrrp_data->static_addresses = alloc_list(free_ipaddress, dump_ipaddress); alloc_ipaddress(vrrp_data->static_addresses, strvec, NULL); } /* Static routes facility function */ void alloc_sroute(vector_t *strvec) { if (LIST_ISEMPTY(vrrp_data->static_routes)) vrrp_data->static_routes = alloc_list(free_iproute, dump_iproute); alloc_route(vrrp_data->static_routes, strvec); } /* VRRP facility functions */ static void free_vgroup(void *data) { vrrp_sgroup_t *vgroup = data; FREE(vgroup->gname); free_strvec(vgroup->iname); free_list(vgroup->index_list); FREE_PTR(vgroup->script_backup); FREE_PTR(vgroup->script_master); FREE_PTR(vgroup->script_fault); FREE_PTR(vgroup->script); FREE(vgroup); } static void dump_vgroup(void *data) { vrrp_sgroup_t *vgroup = data; int i; char *str; log_message(LOG_INFO, " VRRP Sync Group = %s, %s", vgroup->gname, (vgroup->state == VRRP_STATE_MAST) ? "MASTER" : "BACKUP"); for (i = 0; i < vector_size(vgroup->iname); i++) { str = vector_slot(vgroup->iname, i); log_message(LOG_INFO, " monitor = %s", str); } if (vgroup->global_tracking) log_message(LOG_INFO, " Same tracking for all VRRP instances"); if (vgroup->script_backup) log_message(LOG_INFO, " Backup state transition script = %s", vgroup->script_backup); if (vgroup->script_master) log_message(LOG_INFO, " Master state transition script = %s", vgroup->script_master); if (vgroup->script_fault) log_message(LOG_INFO, " Fault state transition script = %s", vgroup->script_fault); if (vgroup->script) log_message(LOG_INFO, " Generic state transition script = '%s'", vgroup->script); if (vgroup->smtp_alert) log_message(LOG_INFO, " Using smtp notification"); } static void free_vscript(void *data) { vrrp_script_t *vscript = data; FREE(vscript->sname); FREE_PTR(vscript->script); FREE(vscript); } static void dump_vscript(void *data) { vrrp_script_t *vscript = data; char *str; log_message(LOG_INFO, " VRRP Script = %s", vscript->sname); log_message(LOG_INFO, " Command = %s", vscript->script); log_message(LOG_INFO, " Interval = %d sec", vscript->interval / TIMER_HZ); log_message(LOG_INFO, " Timeout = %d sec", vscript->timeout / TIMER_HZ); log_message(LOG_INFO, " Weight = %d", vscript->weight); log_message(LOG_INFO, " Rise = %d", vscript->rise); log_message(LOG_INFO, " Fall = %d", vscript->fall); switch (vscript->result) { case VRRP_SCRIPT_STATUS_INIT: str = "INIT"; break; case VRRP_SCRIPT_STATUS_INIT_GOOD: str = "INIT/GOOD"; break; case VRRP_SCRIPT_STATUS_DISABLED: str = "DISABLED"; break; default: str = (vscript->result >= vscript->rise) ? "GOOD" : "BAD"; } log_message(LOG_INFO, " Status = %s", str); } /* Socket pool functions */ static void free_sock(void *sock_data) { sock_t *sock = sock_data; interface_t *ifp; /* First of all cancel pending thread */ thread_cancel(sock->thread); /* Close related socket */ if (sock->fd_in > 0) { ifp = if_get_by_ifindex(sock->ifindex); if (sock->unicast) { close(sock->fd_in); } else { if_leave_vrrp_group(sock->family, sock->fd_in, ifp); } } if (sock->fd_out > 0) close(sock->fd_out); FREE(sock_data); } static void dump_sock(void *sock_data) { sock_t *sock = sock_data; log_message(LOG_INFO, "VRRP sockpool: [ifindex(%d), proto(%d), unicast(%d), fd(%d,%d)]" , sock->ifindex , sock->proto , sock->unicast , sock->fd_in , sock->fd_out); } static void free_unicast_peer(void *data) { FREE(data); } static void dump_unicast_peer(void *data) { struct sockaddr_storage *peer = data; log_message(LOG_INFO, " %s", inet_sockaddrtos(peer)); } static void free_vrrp(void *data) { vrrp_t *vrrp = data; element e; FREE(vrrp->iname); FREE_PTR(vrrp->send_buffer); FREE_PTR(vrrp->lvs_syncd_if); FREE_PTR(vrrp->script_backup); FREE_PTR(vrrp->script_master); FREE_PTR(vrrp->script_fault); FREE_PTR(vrrp->script_stop); FREE_PTR(vrrp->script); FREE(vrrp->ipsecah_counter); if (!LIST_ISEMPTY(vrrp->track_ifp)) for (e = LIST_HEAD(vrrp->track_ifp); e; ELEMENT_NEXT(e)) FREE(ELEMENT_DATA(e)); free_list(vrrp->track_ifp); if (!LIST_ISEMPTY(vrrp->track_script)) for (e = LIST_HEAD(vrrp->track_script); e; ELEMENT_NEXT(e)) FREE(ELEMENT_DATA(e)); free_list(vrrp->track_script); free_list(vrrp->unicast_peer); free_list(vrrp->vip); free_list(vrrp->evip); free_list(vrrp->vroutes); FREE(vrrp); } static void dump_vrrp(void *data) { vrrp_t *vrrp = data; char auth_data[sizeof(vrrp->auth_data) + 1]; log_message(LOG_INFO, " VRRP Instance = %s", vrrp->iname); if (vrrp->family == AF_INET6) log_message(LOG_INFO, " Using Native IPv6"); if (vrrp->init_state == VRRP_STATE_BACK) log_message(LOG_INFO, " Want State = BACKUP"); else log_message(LOG_INFO, " Want State = MASTER"); log_message(LOG_INFO, " Runing on device = %s", IF_NAME(vrrp->ifp)); if (vrrp->dont_track_primary) log_message(LOG_INFO, " VRRP interface tracking disabled"); if (vrrp->saddr.ss_family) log_message(LOG_INFO, " Using src_ip = %s" , inet_sockaddrtos(&vrrp->saddr)); if (vrrp->lvs_syncd_if) log_message(LOG_INFO, " Runing LVS sync daemon on interface = %s", vrrp->lvs_syncd_if); if (vrrp->garp_delay) log_message(LOG_INFO, " Gratuitous ARP delay = %d", vrrp->garp_delay/TIMER_HZ); if (vrrp->garp_refresh) log_message(LOG_INFO, " Gratuitous ARP refresh timer = %d", vrrp->garp_refresh/TIMER_HZ); log_message(LOG_INFO, " Virtual Router ID = %d", vrrp->vrid); log_message(LOG_INFO, " Priority = %d", vrrp->base_priority); log_message(LOG_INFO, " Advert interval = %dsec", vrrp->adver_int / TIMER_HZ); if (vrrp->nopreempt) log_message(LOG_INFO, " Preempt disabled"); if (vrrp->preempt_delay) log_message(LOG_INFO, " Preempt delay = %ld secs", vrrp->preempt_delay / TIMER_HZ); if (vrrp->auth_type) { log_message(LOG_INFO, " Authentication type = %s", (vrrp->auth_type == VRRP_AUTH_AH) ? "IPSEC_AH" : "SIMPLE_PASSWORD"); /* vrrp->auth_data is not \0 terminated */ memcpy(auth_data, vrrp->auth_data, sizeof(vrrp->auth_data)); auth_data[sizeof(vrrp->auth_data)] = '\0'; log_message(LOG_INFO, " Password = %s", auth_data); } if (!LIST_ISEMPTY(vrrp->track_ifp)) { log_message(LOG_INFO, " Tracked interfaces = %d", LIST_SIZE(vrrp->track_ifp)); dump_list(vrrp->track_ifp); } if (!LIST_ISEMPTY(vrrp->track_script)) { log_message(LOG_INFO, " Tracked scripts = %d", LIST_SIZE(vrrp->track_script)); dump_list(vrrp->track_script); } if (!LIST_ISEMPTY(vrrp->unicast_peer)) { log_message(LOG_INFO, " Unicast Peer = %d", LIST_SIZE(vrrp->unicast_peer)); dump_list(vrrp->unicast_peer); } if (!LIST_ISEMPTY(vrrp->vip)) { log_message(LOG_INFO, " Virtual IP = %d", LIST_SIZE(vrrp->vip)); dump_list(vrrp->vip); } if (!LIST_ISEMPTY(vrrp->evip)) { log_message(LOG_INFO, " Virtual IP Excluded = %d", LIST_SIZE(vrrp->evip)); dump_list(vrrp->evip); } if (!LIST_ISEMPTY(vrrp->vroutes)) { log_message(LOG_INFO, " Virtual Routes = %d", LIST_SIZE(vrrp->vroutes)); dump_list(vrrp->vroutes); } if (vrrp->script_backup) log_message(LOG_INFO, " Backup state transition script = %s", vrrp->script_backup); if (vrrp->script_master) log_message(LOG_INFO, " Master state transition script = %s", vrrp->script_master); if (vrrp->script_fault) log_message(LOG_INFO, " Fault state transition script = %s", vrrp->script_fault); if (vrrp->script_stop) log_message(LOG_INFO, " Stop state transition script = %s", vrrp->script_stop); if (vrrp->script) log_message(LOG_INFO, " Generic state transition script = '%s'", vrrp->script); if (vrrp->smtp_alert) log_message(LOG_INFO, " Using smtp notification"); if (vrrp->vmac_flags & VRRP_VMAC_FL_SET) log_message(LOG_INFO, " Using VRRP VMAC (flags:%s|%s)" , (vrrp->vmac_flags & VRRP_VMAC_FL_UP) ? "UP" : "DOWN" , (vrrp->vmac_flags & VRRP_VMAC_FL_XMITBASE) ? "xmit_base" : "xmit"); } void alloc_vrrp_sync_group(char *gname) { int size = strlen(gname); vrrp_sgroup_t *new; /* Allocate new VRRP group structure */ new = (vrrp_sgroup_t *) MALLOC(sizeof(vrrp_sgroup_t)); new->gname = (char *) MALLOC(size + 1); new->state = VRRP_STATE_INIT; memcpy(new->gname, gname, size); new->global_tracking = 0; list_add(vrrp_data->vrrp_sync_group, new); } void alloc_vrrp(char *iname) { int size = strlen(iname); seq_counter_t *counter; vrrp_t *new; /* Allocate new VRRP structure */ new = (vrrp_t *) MALLOC(sizeof(vrrp_t)); counter = (seq_counter_t *) MALLOC(sizeof(seq_counter_t)); /* Build the structure */ new->ipsecah_counter = counter; /* Set default values */ new->family = AF_INET; new->wantstate = VRRP_STATE_BACK; new->init_state = VRRP_STATE_BACK; new->adver_int = TIMER_HZ; new->iname = (char *) MALLOC(size + 1); memcpy(new->iname, iname, size); new->quick_sync = 0; list_add(vrrp_data->vrrp, new); } void alloc_vrrp_unicast_peer(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); struct sockaddr_storage *peer = NULL; int ret; if (LIST_ISEMPTY(vrrp->unicast_peer)) vrrp->unicast_peer = alloc_list(free_unicast_peer, dump_unicast_peer); /* Allocate new unicast peer */ peer = (struct sockaddr_storage *) MALLOC(sizeof(struct sockaddr_storage)); ret = inet_stosockaddr(vector_slot(strvec, 0), 0, peer); if (ret < 0) { log_message(LOG_ERR, "Configuration error: VRRP instance[%s] malformed unicast" " peer address[%s]. Skipping..." , vrrp->iname, vector_slot(strvec, 0)); FREE(peer); return; } if (peer->ss_family != vrrp->family) { log_message(LOG_ERR, "Configuration error: VRRP instance[%s] and unicast peer address" "[%s] MUST be of the same family !!! Skipping..." , vrrp->iname, vector_slot(strvec, 0)); FREE(peer); return; } list_add(vrrp->unicast_peer, peer); } void alloc_vrrp_track(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); if (LIST_ISEMPTY(vrrp->track_ifp)) vrrp->track_ifp = alloc_list(NULL, dump_track); alloc_track(vrrp->track_ifp, strvec); } void alloc_vrrp_track_script(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); if (LIST_ISEMPTY(vrrp->track_script)) vrrp->track_script = alloc_list(NULL, dump_track_script); alloc_track_script(vrrp->track_script, strvec); } void alloc_vrrp_vip(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); if (vrrp->ifp == NULL) { log_message(LOG_ERR, "Configuration error: VRRP definition must belong to an interface"); } if (LIST_ISEMPTY(vrrp->vip)) vrrp->vip = alloc_list(free_ipaddress, dump_ipaddress); alloc_ipaddress(vrrp->vip, strvec, vrrp->ifp); } void alloc_vrrp_evip(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); if (LIST_ISEMPTY(vrrp->evip)) vrrp->evip = alloc_list(free_ipaddress, dump_ipaddress); alloc_ipaddress(vrrp->evip, strvec, vrrp->ifp); } void alloc_vrrp_vroute(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); if (LIST_ISEMPTY(vrrp->vroutes)) vrrp->vroutes = alloc_list(free_iproute, dump_iproute); alloc_route(vrrp->vroutes, strvec); } void alloc_vrrp_script(char *sname) { int size = strlen(sname); vrrp_script_t *new; /* Allocate new VRRP group structure */ new = (vrrp_script_t *) MALLOC(sizeof(vrrp_script_t)); new->sname = (char *) MALLOC(size + 1); memcpy(new->sname, sname, size + 1); new->interval = VRRP_SCRIPT_DI * TIMER_HZ; new->timeout = VRRP_SCRIPT_DT * TIMER_HZ; new->weight = VRRP_SCRIPT_DW; new->result = VRRP_SCRIPT_STATUS_INIT; new->inuse = 0; new->rise = 1; new->fall = 1; list_add(vrrp_data->vrrp_script, new); } /* data facility functions */ void alloc_vrrp_buffer(void) { vrrp_buffer = (char *) MALLOC(VRRP_PACKET_TEMP_LEN); } void free_vrrp_buffer(void) { FREE(vrrp_buffer); } vrrp_data_t * alloc_vrrp_data(void) { vrrp_data_t *new; new = (vrrp_data_t *) MALLOC(sizeof(vrrp_data_t)); new->vrrp = alloc_list(free_vrrp, dump_vrrp); new->vrrp_index = alloc_mlist(NULL, NULL, 255+1); new->vrrp_index_fd = alloc_mlist(NULL, NULL, 1024+1); new->vrrp_sync_group = alloc_list(free_vgroup, dump_vgroup); new->vrrp_script = alloc_list(free_vscript, dump_vscript); new->vrrp_socket_pool = alloc_list(free_sock, dump_sock); return new; } void free_vrrp_data(vrrp_data_t * data) { free_list(data->static_addresses); free_list(data->static_routes); free_mlist(data->vrrp_index, 255+1); free_mlist(data->vrrp_index_fd, 1024+1); free_list(data->vrrp); free_list(data->vrrp_sync_group); free_list(data->vrrp_script); FREE(data); } void dump_vrrp_data(vrrp_data_t * data) { if (!LIST_ISEMPTY(data->static_addresses)) { log_message(LOG_INFO, "------< Static Addresses >------"); dump_list(data->static_addresses); } if (!LIST_ISEMPTY(data->static_routes)) { log_message(LOG_INFO, "------< Static Routes >------"); dump_list(data->static_routes); } if (!LIST_ISEMPTY(data->vrrp)) { log_message(LOG_INFO, "------< VRRP Topology >------"); dump_list(data->vrrp); } if (!LIST_ISEMPTY(data->vrrp_sync_group)) { log_message(LOG_INFO, "------< VRRP Sync groups >------"); dump_list(data->vrrp_sync_group); } if (!LIST_ISEMPTY(data->vrrp_script)) { log_message(LOG_INFO, "------< VRRP Scripts >------"); dump_list(data->vrrp_script); } } keepalived-1.2.13/keepalived/vrrp/vrrp_snmp.c0000664000175000017500000010731012211121152021007 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: SNMP agent * * Author: Vincent Bernat * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "vrrp.h" #include "vrrp_snmp.h" #include "vrrp_data.h" #include "vrrp_track.h" #include "vrrp_ipaddress.h" #include "vrrp_iproute.h" #include "config.h" #include "vector.h" #include "list.h" #include "logger.h" #include "global_data.h" /* Convert VRRP state to SNMP state */ static unsigned long vrrp_snmp_state(int state) { return (statevrrp_script)) == NULL) return NULL; switch (vp->magic) { case VRRP_SNMP_SCRIPT_NAME: *var_len = strlen(scr->sname); return (u_char *)scr->sname; case VRRP_SNMP_SCRIPT_COMMAND: *var_len = strlen(scr->script); return (u_char *)scr->script; case VRRP_SNMP_SCRIPT_INTERVAL: long_ret = scr->interval / TIMER_HZ; return (u_char *)&long_ret; case VRRP_SNMP_SCRIPT_WEIGHT: long_ret = scr->weight; return (u_char *)&long_ret; case VRRP_SNMP_SCRIPT_RESULT: switch (scr->result) { case VRRP_SCRIPT_STATUS_INIT: long_ret = 1; break; case VRRP_SCRIPT_STATUS_INIT_GOOD: long_ret = 4; break; case VRRP_SCRIPT_STATUS_DISABLED: long_ret = 0; break; default: long_ret = (scr->result >= scr->rise) ? 3 : 2; } return (u_char *)&long_ret; case VRRP_SNMP_SCRIPT_RISE: long_ret = scr->rise; return (u_char *)&long_ret; case VRRP_SNMP_SCRIPT_FALL: long_ret = scr->fall; return (u_char *)&long_ret; default: break; } return NULL; } /* Header function using a FSM. `state' is the initial state, either HEADER_STATE_STATIC_ADDRESS or HEADER_STATE_STATIC_ROUTE. We return the matching address or route. */ static void* vrrp_header_ar_table(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method, int *state) { oid *target, current[2], best[2]; int result, target_len; element e1 = NULL, e2; void *el, *bel = NULL; list l2; int curinstance = 0; int curstate, nextstate; if ((result = snmp_oid_compare(name, *length, vp->name, vp->namelen)) < 0) { memcpy(name, vp->name, sizeof(oid) * vp->namelen); *length = vp->namelen; } *write_method = 0; *var_len = sizeof(long); /* We search the best match: equal if exact, the lower OID in the set of the OID strictly superior to the target otherwise. */ best[0] = best[1] = MAX_SUBID; /* Our best match */ target = &name[vp->namelen]; /* Our target match */ target_len = *length - vp->namelen; nextstate = *state; while (nextstate != HEADER_STATE_END) { curstate = nextstate; switch (curstate) { case HEADER_STATE_STATIC_ADDRESS: /* Try static addresses */ l2 = vrrp_data->static_addresses; current[1] = 0; nextstate = HEADER_STATE_VIRTUAL_ADDRESS; break; case HEADER_STATE_VIRTUAL_ADDRESS: /* Try virtual addresses */ if (LIST_ISEMPTY(vrrp_data->vrrp)) { nextstate = HEADER_STATE_END; continue; } curinstance++; if (e1 == NULL) e1 = LIST_HEAD(vrrp_data->vrrp); else { ELEMENT_NEXT(e1); if (!e1) { nextstate = HEADER_STATE_END; continue; } } l2 = ((vrrp_t *) ELEMENT_DATA(e1))->vip; current[1] = 0; nextstate = HEADER_STATE_EXCLUDED_VIRTUAL_ADDRESS; break; case HEADER_STATE_EXCLUDED_VIRTUAL_ADDRESS: /* Try excluded virtual addresses */ l2 = ((vrrp_t *)ELEMENT_DATA(e1))->evip; nextstate = HEADER_STATE_VIRTUAL_ADDRESS; break; case HEADER_STATE_STATIC_ROUTE: /* Try static routes */ l2 = vrrp_data->static_routes; current[1] = 0; nextstate = HEADER_STATE_VIRTUAL_ROUTE; break; case HEADER_STATE_VIRTUAL_ROUTE: /* Try virtual routes */ if (LIST_ISEMPTY(vrrp_data->vrrp) || ((e1 != NULL) && (ELEMENT_NEXT(e1), !e1))) { nextstate = HEADER_STATE_END; continue; } curinstance++; if (e1 == NULL) e1 = LIST_HEAD(vrrp_data->vrrp); l2 = ((vrrp_t *)ELEMENT_DATA(e1))->vroutes; current[1] = 0; nextstate = HEADER_STATE_VIRTUAL_ROUTE; break; default: return NULL; /* Big problem! */ } if (target_len && (curinstance < target[0])) continue; /* Optimization: cannot be part of our set */ if (LIST_ISEMPTY(l2)) continue; for (e2 = LIST_HEAD(l2); e2; ELEMENT_NEXT(e2)) { el = ELEMENT_DATA(e2); current[0] = curinstance; current[1]++; if ((result = snmp_oid_compare(current, 2, target, target_len)) < 0) continue; if ((result == 0) && !exact) continue; if (result == 0) { return el; } if (snmp_oid_compare(current, 2, best, 2) < 0) { /* This is our best match */ memcpy(best, current, sizeof(oid) * 2); bel = el; *state = curstate; /* Optimization: (e1,e2) is strictly increasing, this is the lower element of our target set. */ nextstate = HEADER_STATE_END; break; } } } if (bel == NULL) /* No best match */ return NULL; if (exact) /* No exact match */ return NULL; /* Let's use our best match */ memcpy(target, best, sizeof(oid) * 2); *length = vp->namelen + 2; return bel; } static u_char* vrrp_snmp_address(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static unsigned long long_ret; ip_address_t *addr; int state = HEADER_STATE_STATIC_ADDRESS; if ((addr = (ip_address_t *) vrrp_header_ar_table(vp, name, length, exact, var_len, write_method, &state)) == NULL) return NULL; switch (vp->magic) { case VRRP_SNMP_ADDRESS_ADDRESSTYPE: long_ret = (addr->ifa.ifa_family == AF_INET6)?2:1; return (u_char *)&long_ret; case VRRP_SNMP_ADDRESS_VALUE: if (addr->ifa.ifa_family == AF_INET6) { *var_len = 16; return (u_char *)&addr->u.sin6_addr; } else { *var_len = 4; return (u_char *)&addr->u.sin.sin_addr; } break; case VRRP_SNMP_ADDRESS_BROADCAST: if (addr->ifa.ifa_family == AF_INET6) break; *var_len = 4; return (u_char *)&addr->u.sin.sin_brd; case VRRP_SNMP_ADDRESS_MASK: long_ret = addr->ifa.ifa_prefixlen; return (u_char *)&long_ret; case VRRP_SNMP_ADDRESS_SCOPE: long_ret = snmp_scope(addr->ifa.ifa_scope); return (u_char *)&long_ret; case VRRP_SNMP_ADDRESS_IFINDEX: long_ret = addr->ifa.ifa_index; return (u_char *)&long_ret; case VRRP_SNMP_ADDRESS_IFNAME: *var_len = strlen(addr->ifp->ifname); return (u_char *)addr->ifp->ifname; case VRRP_SNMP_ADDRESS_IFALIAS: if (addr->label) { *var_len = strlen(addr->label); return (u_char*)addr->label; } break; case VRRP_SNMP_ADDRESS_ISSET: long_ret = (addr->set)?1:2; return (u_char *)&long_ret; case VRRP_SNMP_ADDRESS_ISADVERTISED: long_ret = (state == HEADER_STATE_VIRTUAL_ADDRESS)?1:2; return (u_char *)&long_ret; default: return NULL; } /* If we are here, we asked for a non existent data. Try the next one. */ if (!exact && (name[*length-1] < MAX_SUBID)) return vrrp_snmp_address(vp, name, length, exact, var_len, write_method); return NULL; } static u_char* vrrp_snmp_route(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static unsigned long long_ret; ip_route_t *route; int state = HEADER_STATE_STATIC_ROUTE; if ((route = (ip_route_t *) vrrp_header_ar_table(vp, name, length, exact, var_len, write_method, &state)) == NULL) return NULL; switch (vp->magic) { case VRRP_SNMP_ROUTE_ADDRESSTYPE: long_ret = 1; /* IPv4 only */ return (u_char *)&long_ret; case VRRP_SNMP_ROUTE_DESTINATION: *var_len = 4; return (u_char *)&route->dst; case VRRP_SNMP_ROUTE_DESTINATIONMASK: long_ret = route->dmask; return (u_char *)&long_ret; case VRRP_SNMP_ROUTE_GATEWAY: *var_len = 4; return (u_char *)&route->gw; case VRRP_SNMP_ROUTE_SECONDARYGATEWAY: if (route->gw2) { *var_len = 4; return (u_char *)&route->gw2; } break; case VRRP_SNMP_ROUTE_SOURCE: *var_len = 4; return (u_char *)&route->src; case VRRP_SNMP_ROUTE_METRIC: long_ret = route->metric; return (u_char *)&long_ret; case VRRP_SNMP_ROUTE_SCOPE: long_ret = snmp_scope(route->scope); return (u_char *)&long_ret; case VRRP_SNMP_ROUTE_TYPE: if (route->blackhole) long_ret = 3; else if (route->gw2) long_ret = 2; else long_ret = 1; return (u_char *)&long_ret; case VRRP_SNMP_ROUTE_IFINDEX: long_ret = route->index; return (u_char *)&long_ret; case VRRP_SNMP_ROUTE_IFNAME: if (route->index) { *var_len = strlen(IF_NAME(if_get_by_ifindex(route->index))); return (u_char *)&IF_NAME(if_get_by_ifindex(route->index)); } break; case VRRP_SNMP_ROUTE_ROUTINGTABLE: long_ret = route->table; return (u_char *)&long_ret; case VRRP_SNMP_ROUTE_ISSET: long_ret = (route->set)?1:2; return (u_char *)&long_ret; default: return NULL; } /* If we are here, we asked for a non existent data. Try the next one. */ if (!exact && (name[*length-1] < MAX_SUBID)) return vrrp_snmp_route(vp, name, length, exact, var_len, write_method); return NULL; } static u_char* vrrp_snmp_syncgroup(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static unsigned long long_ret; vrrp_sgroup_t *group; if ((group = (vrrp_sgroup_t *) snmp_header_list_table(vp, name, length, exact, var_len, write_method, vrrp_data->vrrp_sync_group)) == NULL) return NULL; switch (vp->magic) { case VRRP_SNMP_SYNCGROUP_NAME: *var_len = strlen(group->gname); return (u_char *)group->gname; case VRRP_SNMP_SYNCGROUP_STATE: long_ret = vrrp_snmp_state(group->state); return (u_char *)&long_ret; case VRRP_SNMP_SYNCGROUP_SMTPALERT: long_ret = group->smtp_alert?1:2; return (u_char *)&long_ret; case VRRP_SNMP_SYNCGROUP_NOTIFYEXEC: long_ret = group->notify_exec?1:2; return (u_char *)&long_ret; case VRRP_SNMP_SYNCGROUP_SCRIPTMASTER: if (group->script_master) { *var_len = strlen(group->script_master); return (u_char *)group->script_master; } break; case VRRP_SNMP_SYNCGROUP_SCRIPTBACKUP: if (group->script_backup) { *var_len = strlen(group->script_backup); return (u_char *)group->script_backup; } break; case VRRP_SNMP_SYNCGROUP_SCRIPTFAULT: if (group->script_fault) { *var_len = strlen(group->script_fault); return (u_char *)group->script_fault; } break; case VRRP_SNMP_SYNCGROUP_SCRIPT: if (group->script) { *var_len = strlen(group->script); return (u_char *)group->script; } break; default: return NULL; } /* If we are here, we asked for a non existent data. Try the next one. */ if (!exact && (name[*length-1] < MAX_SUBID)) return vrrp_snmp_syncgroup(vp, name, length, exact, var_len, write_method); return NULL; } static u_char* vrrp_snmp_syncgroupmember(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { oid *target, current[2], best[2]; int result, target_len; int curgroup, curinstance; char *instance, *binstance = NULL; element e; vrrp_sgroup_t *group; if ((result = snmp_oid_compare(name, *length, vp->name, vp->namelen)) < 0) { memcpy(name, vp->name, sizeof(oid) * vp->namelen); *length = vp->namelen; } *write_method = 0; *var_len = sizeof(long); if (LIST_ISEMPTY(vrrp_data->vrrp_sync_group)) return NULL; /* We search the best match: equal if exact, the lower OID in the set of the OID strictly superior to the target otherwise. */ best[0] = best[1] = MAX_SUBID; /* Our best match */ target = &name[vp->namelen]; /* Our target match */ target_len = *length - vp->namelen; curgroup = 0; for (e = LIST_HEAD(vrrp_data->vrrp_sync_group); e; ELEMENT_NEXT(e)) { group = ELEMENT_DATA(e); curgroup++; if (target_len && (curgroup < target[0])) continue; /* Optimization: cannot be part of our set */ if (binstance) break; /* Optimization: cannot be the lower anymore, see break below */ vector_foreach_slot(group->iname, instance, curinstance) { /* We build our current match */ current[0] = curgroup; current[1] = curinstance + 1; /* And compare it to our target match */ if ((result = snmp_oid_compare(current, 2, target, target_len)) < 0) continue; if ((result == 0) && !exact) continue; if (result == 0) { /* Got an exact match and asked for it */ *var_len = strlen(instance); return (u_char *)instance; } if (snmp_oid_compare(current, 2, best, 2) < 0) { /* This is our best match */ memcpy(best, current, sizeof(oid) * 2); binstance = instance; /* (current[0],current[1]) are strictly increasing, this is our lower element of our set */ break; } } } if (binstance == NULL) /* No best match */ return NULL; if (exact) /* No exact match */ return NULL; /* Let's use our best match */ memcpy(target, best, sizeof(oid) * 2); *length = vp->namelen + 2; *var_len = strlen(binstance); return (u_char*)binstance; } static vrrp_t * _get_instance(oid *name, size_t name_len) { int instance; element e; vrrp_t *vrrp = NULL; if (name_len < 1) return NULL; instance = name[name_len - 1]; if (LIST_ISEMPTY(vrrp_data->vrrp)) return NULL; for (e = LIST_HEAD(vrrp_data->vrrp); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); if (--instance == 0) break; } return vrrp; } static int vrrp_snmp_instance_priority(int action, u_char *var_val, u_char var_val_type, size_t var_val_len, u_char *statP, oid *name, size_t name_len) { vrrp_t *vrrp = NULL; switch (action) { case RESERVE1: /* Check that the proposed priority is acceptable */ if (var_val_type != ASN_INTEGER) return SNMP_ERR_WRONGTYPE; if (var_val_len > sizeof(long)) return SNMP_ERR_WRONGLENGTH; if (VRRP_IS_BAD_PRIORITY((long)(*var_val))) return SNMP_ERR_WRONGVALUE; break; case RESERVE2: /* Check that we can find the instance. We should. */ case COMMIT: /* Find the instance */ vrrp = _get_instance(name, name_len); if (!vrrp) return SNMP_ERR_NOSUCHNAME; if (action == RESERVE2) break; /* Commit: change values. There is no way to fail. */ log_message(LOG_INFO, "VRRP_Instance(%s) base priority changed from" " %d to %d via SNMP.", vrrp->iname, vrrp->base_priority, (long)(*var_val)); vrrp->base_priority = (long)(*var_val); /* If we the instance is not part of a sync group, the effective priority will be recomputed by some thread. Otherwise, we should set it equal to the base priority. */ if (vrrp->sync) vrrp->effective_priority = vrrp->base_priority; break; } return SNMP_ERR_NOERROR; } static int vrrp_snmp_instance_preempt(int action, u_char *var_val, u_char var_val_type, size_t var_val_len, u_char *statP, oid *name, size_t name_len) { vrrp_t *vrrp = NULL; switch (action) { case RESERVE1: /* Check that the proposed value is acceptable */ if (var_val_type != ASN_INTEGER) return SNMP_ERR_WRONGTYPE; if (var_val_len > sizeof(long)) return SNMP_ERR_WRONGLENGTH; switch ((long)(*var_val)) { case 1: /* enable preemption */ case 2: /* disable preemption */ break; default: return SNMP_ERR_WRONGVALUE; } break; case RESERVE2: /* Check that we can find the instance. We should. */ case COMMIT: /* Find the instance */ vrrp = _get_instance(name, name_len); if (!vrrp) return SNMP_ERR_NOSUCHNAME; if (action == RESERVE2) break; /* Commit: change values. There is no way to fail. */ switch ((long)(*var_val)) { case 1: log_message(LOG_INFO, "VRRP_Instance(%s) preemption enabled with SNMP", vrrp->iname); vrrp->nopreempt = 0; break; case 2: log_message(LOG_INFO, "VRRP_Instance(%s) preemption disabled with SNMP", vrrp->iname); vrrp->nopreempt = 1; break; } break; } return SNMP_ERR_NOERROR; } static u_char* vrrp_snmp_instance(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static unsigned long long_ret; vrrp_t *rt; if ((rt = (vrrp_t *)snmp_header_list_table(vp, name, length, exact, var_len, write_method, vrrp_data->vrrp)) == NULL) return NULL; switch (vp->magic) { case VRRP_SNMP_INSTANCE_NAME: *var_len = strlen(rt->iname); return (u_char *)rt->iname; case VRRP_SNMP_INSTANCE_VIRTUALROUTERID: long_ret = rt->vrid; return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_STATE: long_ret = vrrp_snmp_state(rt->state); return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_INITIALSTATE: long_ret = vrrp_snmp_state(rt->init_state); return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_WANTEDSTATE: long_ret = vrrp_snmp_state(rt->wantstate); return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_BASEPRIORITY: long_ret = rt->base_priority; *write_method = vrrp_snmp_instance_priority; return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_EFFECTIVEPRIORITY: long_ret = rt->effective_priority; return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_VIPSENABLED: long_ret = rt->vipset?1:2; return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_PRIMARYINTERFACE: *var_len = strlen(rt->ifp->ifname); return (u_char *)&rt->ifp->ifname; case VRRP_SNMP_INSTANCE_TRACKPRIMARYIF: long_ret = rt->track_ifp?1:2; return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_ADVERTISEMENTSINT: long_ret = rt->adver_int / TIMER_HZ; return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_PREEMPT: long_ret = rt->nopreempt?2:1; *write_method = vrrp_snmp_instance_preempt; return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_PREEMPTDELAY: long_ret = rt->preempt_delay / TIMER_HZ; return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_AUTHTYPE: long_ret = rt->auth_type; return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_USELVSSYNCDAEMON: long_ret = (rt->lvs_syncd_if)?1:2; return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_LVSSYNCINTERFACE: if (rt->lvs_syncd_if) { *var_len = strlen(rt->lvs_syncd_if); return (u_char *)rt->lvs_syncd_if; } break; case VRRP_SNMP_INSTANCE_SYNCGROUP: if (rt->sync) { *var_len = strlen(rt->sync->gname); return (u_char *)rt->sync->gname; } break; case VRRP_SNMP_INSTANCE_GARPDELAY: long_ret = rt->garp_delay / TIMER_HZ; return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_SMTPALERT: long_ret = rt->smtp_alert?1:2; return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_NOTIFYEXEC: long_ret = rt->notify_exec?1:2; return (u_char *)&long_ret; case VRRP_SNMP_INSTANCE_SCRIPTMASTER: if (rt->script_master) { *var_len = strlen(rt->script_master); return (u_char *)rt->script_master; } break; case VRRP_SNMP_INSTANCE_SCRIPTBACKUP: if (rt->script_backup) { *var_len = strlen(rt->script_backup); return (u_char *)rt->script_backup; } break; case VRRP_SNMP_INSTANCE_SCRIPTFAULT: if (rt->script_fault) { *var_len = strlen(rt->script_fault); return (u_char *)rt->script_fault; } break; case VRRP_SNMP_INSTANCE_SCRIPTSTOP: if (rt->script_stop) { *var_len = strlen(rt->script_stop); return (u_char *)rt->script_stop; } break; case VRRP_SNMP_INSTANCE_SCRIPT: if (rt->script) { *var_len = strlen(rt->script); return (u_char *)rt->script; } break; default: return NULL; } /* If we are here, we asked for a non existent data. Try the next one. */ if (!exact && (name[*length-1] < MAX_SUBID)) return vrrp_snmp_instance(vp, name, length, exact, var_len, write_method); return NULL; } static u_char* vrrp_snmp_trackedinterface(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static unsigned long long_ret; oid *target, current[2], best[2]; int result, target_len; int curinstance; element e1, e2; vrrp_t *instance; tracked_if_t *ifp, *bifp = NULL; if ((result = snmp_oid_compare(name, *length, vp->name, vp->namelen)) < 0) { memcpy(name, vp->name, sizeof(oid) * vp->namelen); *length = vp->namelen; } *write_method = 0; *var_len = sizeof(long); if (LIST_ISEMPTY(vrrp_data->vrrp)) return NULL; /* We search the best match: equal if exact, the lower OID in the set of the OID strictly superior to the target otherwise. */ best[0] = best[1] = MAX_SUBID; /* Our best match */ target = &name[vp->namelen]; /* Our target match */ target_len = *length - vp->namelen; curinstance = 0; for (e1 = LIST_HEAD(vrrp_data->vrrp); e1; ELEMENT_NEXT(e1)) { instance = ELEMENT_DATA(e1); curinstance++; if (target_len && (curinstance < target[0])) continue; /* Optimization: cannot be part of our set */ if (target_len && bifp && (curinstance > target[0] + 1)) break; /* Optimization: cannot be the lower anymore */ if (LIST_ISEMPTY(instance->track_ifp)) continue; for (e2 = LIST_HEAD(instance->track_ifp); e2; ELEMENT_NEXT(e2)) { ifp = ELEMENT_DATA(e2); /* We build our current match */ current[0] = curinstance; current[1] = ifp->ifp->ifindex; /* And compare it to our target match */ if ((result = snmp_oid_compare(current, 2, target, target_len)) < 0) continue; if ((result == 0) && !exact) continue; if (result == 0) { /* Got an exact match and asked for it */ bifp = ifp; goto trackedinterface_found; } if (snmp_oid_compare(current, 2, best, 2) < 0) { /* This is our best match */ memcpy(best, current, sizeof(oid) * 2); bifp = ifp; } } } if (bifp == NULL) /* No best match */ return NULL; if (exact) /* No exact match */ return NULL; /* Let's use our best match */ memcpy(target, best, sizeof(oid) * 2); *length = vp->namelen + 2; trackedinterface_found: switch (vp->magic) { case VRRP_SNMP_TRACKEDINTERFACE_NAME: *var_len = strlen(bifp->ifp->ifname); return (u_char *)bifp->ifp->ifname; case VRRP_SNMP_TRACKEDINTERFACE_WEIGHT: long_ret = bifp->weight; return (u_char *)&long_ret; } return NULL; } static u_char* vrrp_snmp_trackedscript(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static unsigned long long_ret; oid *target, current[2], best[2]; int result, target_len; int curinstance, curscr; element e1, e2; vrrp_t *instance; tracked_sc_t *scr, *bscr = NULL; if ((result = snmp_oid_compare(name, *length, vp->name, vp->namelen)) < 0) { memcpy(name, vp->name, sizeof(oid) * vp->namelen); *length = vp->namelen; } *write_method = 0; *var_len = sizeof(long); if (LIST_ISEMPTY(vrrp_data->vrrp)) return NULL; /* We search the best match: equal if exact, the lower OID in the set of the OID strictly superior to the target otherwise. */ best[0] = best[1] = MAX_SUBID; /* Our best match */ target = &name[vp->namelen]; /* Our target match */ target_len = *length - vp->namelen; curinstance = 0; for (e1 = LIST_HEAD(vrrp_data->vrrp); e1; ELEMENT_NEXT(e1)) { instance = ELEMENT_DATA(e1); curinstance++; if (target_len && (curinstance < target[0])) continue; /* Optimization: cannot be part of our set */ if (bscr) break; /* Optimization, see below */ if (LIST_ISEMPTY(instance->track_script)) continue; curscr = 0; for (e2 = LIST_HEAD(instance->track_script); e2; ELEMENT_NEXT(e2)) { scr = ELEMENT_DATA(e2); curscr++; /* We build our current match */ current[0] = curinstance; current[1] = curscr; /* And compare it to our target match */ if ((result = snmp_oid_compare(current, 2, target, target_len)) < 0) continue; if ((result == 0) && !exact) continue; if (result == 0) { /* Got an exact match and asked for it */ bscr = scr; goto trackedscript_found; } if (snmp_oid_compare(current, 2, best, 2) < 0) { /* This is our best match */ memcpy(best, current, sizeof(oid) * 2); bscr = scr; /* (current[0],current[1]) are strictly increasing, this is our lower element of our set */ break; } } } if (bscr == NULL) /* No best match */ return NULL; if (exact) /* No exact match */ return NULL; /* Let's use our best match */ memcpy(target, best, sizeof(oid) * 2); *length = vp->namelen + 2; trackedscript_found: switch (vp->magic) { case VRRP_SNMP_TRACKEDSCRIPT_NAME: *var_len = strlen(bscr->scr->sname); return (u_char *)bscr->scr->sname; case VRRP_SNMP_TRACKEDSCRIPT_WEIGHT: long_ret = bscr->weight; return (u_char *)&long_ret; } return NULL; } static oid vrrp_oid[] = {VRRP_OID}; static struct variable8 vrrp_vars[] = { /* vrrpSyncGroupTable */ {VRRP_SNMP_SYNCGROUP_NAME, ASN_OCTET_STR, RONLY, vrrp_snmp_syncgroup, 3, {1, 1, 2}}, {VRRP_SNMP_SYNCGROUP_STATE, ASN_INTEGER, RONLY, vrrp_snmp_syncgroup, 3, {1, 1, 3}}, {VRRP_SNMP_SYNCGROUP_SMTPALERT, ASN_INTEGER, RONLY, vrrp_snmp_syncgroup, 3, {1, 1, 4}}, {VRRP_SNMP_SYNCGROUP_NOTIFYEXEC, ASN_INTEGER, RONLY, vrrp_snmp_syncgroup, 3, {1, 1, 5}}, {VRRP_SNMP_SYNCGROUP_SCRIPTMASTER, ASN_OCTET_STR, RONLY, vrrp_snmp_syncgroup, 3, {1, 1, 6}}, {VRRP_SNMP_SYNCGROUP_SCRIPTBACKUP, ASN_OCTET_STR, RONLY, vrrp_snmp_syncgroup, 3, {1, 1, 7}}, {VRRP_SNMP_SYNCGROUP_SCRIPTFAULT, ASN_OCTET_STR, RONLY, vrrp_snmp_syncgroup, 3, {1, 1, 8}}, {VRRP_SNMP_SYNCGROUP_SCRIPT, ASN_OCTET_STR, RONLY, vrrp_snmp_syncgroup, 3, {1, 1, 9}}, /* vrrpSyncGroupMemberTable */ {VRRP_SNMP_SYNCGROUPMEMBER_NAME, ASN_OCTET_STR, RONLY, vrrp_snmp_syncgroupmember, 3, {2, 1, 2}}, /* vrrpInstanceTable */ {VRRP_SNMP_INSTANCE_NAME, ASN_OCTET_STR, RONLY, vrrp_snmp_instance, 3, {3, 1, 2}}, {VRRP_SNMP_INSTANCE_VIRTUALROUTERID, ASN_UNSIGNED, RONLY, vrrp_snmp_instance, 3, {3, 1, 3}}, {VRRP_SNMP_INSTANCE_STATE, ASN_INTEGER, RONLY, vrrp_snmp_instance, 3, {3, 1, 4}}, {VRRP_SNMP_INSTANCE_INITIALSTATE, ASN_INTEGER, RONLY, vrrp_snmp_instance, 3, {3, 1, 5}}, {VRRP_SNMP_INSTANCE_WANTEDSTATE, ASN_INTEGER, RONLY, vrrp_snmp_instance, 3, {3, 1, 6}}, {VRRP_SNMP_INSTANCE_BASEPRIORITY, ASN_INTEGER, RWRITE, vrrp_snmp_instance, 3, {3, 1, 7}}, {VRRP_SNMP_INSTANCE_EFFECTIVEPRIORITY, ASN_INTEGER, RONLY, vrrp_snmp_instance, 3, {3, 1, 8}}, {VRRP_SNMP_INSTANCE_VIPSENABLED, ASN_INTEGER, RONLY, vrrp_snmp_instance, 3, {3, 1, 9}}, {VRRP_SNMP_INSTANCE_PRIMARYINTERFACE, ASN_OCTET_STR, RONLY, vrrp_snmp_instance, 3, {3, 1, 10}}, {VRRP_SNMP_INSTANCE_TRACKPRIMARYIF, ASN_INTEGER, RONLY, vrrp_snmp_instance, 3, {3, 1, 11}}, {VRRP_SNMP_INSTANCE_ADVERTISEMENTSINT, ASN_UNSIGNED, RONLY, vrrp_snmp_instance, 3, {3, 1, 12}}, {VRRP_SNMP_INSTANCE_PREEMPT, ASN_INTEGER, RWRITE, vrrp_snmp_instance, 3, {3, 1, 13}}, {VRRP_SNMP_INSTANCE_PREEMPTDELAY, ASN_UNSIGNED, RONLY, vrrp_snmp_instance, 3, {3, 1, 14}}, {VRRP_SNMP_INSTANCE_AUTHTYPE, ASN_INTEGER, RONLY, vrrp_snmp_instance, 3, {3, 1, 15}}, {VRRP_SNMP_INSTANCE_USELVSSYNCDAEMON, ASN_INTEGER, RONLY, vrrp_snmp_instance, 3, {3, 1, 16}}, {VRRP_SNMP_INSTANCE_LVSSYNCINTERFACE, ASN_OCTET_STR, RONLY, vrrp_snmp_instance, 3, {3, 1, 17}}, {VRRP_SNMP_INSTANCE_SYNCGROUP, ASN_OCTET_STR, RONLY, vrrp_snmp_instance, 3, {3, 1, 18}}, {VRRP_SNMP_INSTANCE_GARPDELAY, ASN_UNSIGNED, RONLY, vrrp_snmp_instance, 3, {3, 1, 19}}, {VRRP_SNMP_INSTANCE_SMTPALERT, ASN_INTEGER, RONLY, vrrp_snmp_instance, 3, {3, 1, 20}}, {VRRP_SNMP_INSTANCE_NOTIFYEXEC, ASN_INTEGER, RONLY, vrrp_snmp_instance, 3, {3, 1, 21}}, {VRRP_SNMP_INSTANCE_SCRIPTMASTER, ASN_OCTET_STR, RONLY, vrrp_snmp_instance, 3, {3, 1, 22}}, {VRRP_SNMP_INSTANCE_SCRIPTBACKUP, ASN_OCTET_STR, RONLY, vrrp_snmp_instance, 3, {3, 1, 23}}, {VRRP_SNMP_INSTANCE_SCRIPTFAULT, ASN_OCTET_STR, RONLY, vrrp_snmp_instance, 3, {3, 1, 24}}, {VRRP_SNMP_INSTANCE_SCRIPTSTOP, ASN_OCTET_STR, RONLY, vrrp_snmp_instance, 3, {3, 1, 25}}, {VRRP_SNMP_INSTANCE_SCRIPT, ASN_OCTET_STR, RONLY, vrrp_snmp_instance, 3, {3, 1, 26}}, /* vrrpTrackedInterfaceTable */ {VRRP_SNMP_TRACKEDINTERFACE_NAME, ASN_OCTET_STR, RONLY, vrrp_snmp_trackedinterface, 3, {4, 1, 1}}, {VRRP_SNMP_TRACKEDINTERFACE_WEIGHT, ASN_INTEGER, RONLY, vrrp_snmp_trackedinterface, 3, {4, 1, 2}}, /* vrrpTrackedScriptTable */ {VRRP_SNMP_TRACKEDSCRIPT_NAME, ASN_OCTET_STR, RONLY, vrrp_snmp_trackedscript, 3, {5, 1, 2}}, {VRRP_SNMP_TRACKEDSCRIPT_WEIGHT, ASN_INTEGER, RONLY, vrrp_snmp_trackedscript, 3, {5, 1, 3}}, /* vrrpAddressTable */ {VRRP_SNMP_ADDRESS_ADDRESSTYPE, ASN_INTEGER, RONLY, vrrp_snmp_address, 3, {6, 1, 2}}, {VRRP_SNMP_ADDRESS_VALUE, ASN_OCTET_STR, RONLY, vrrp_snmp_address, 3, {6, 1, 3}}, {VRRP_SNMP_ADDRESS_BROADCAST, ASN_OCTET_STR, RONLY, vrrp_snmp_address, 3, {6, 1, 4}}, {VRRP_SNMP_ADDRESS_MASK, ASN_UNSIGNED, RONLY, vrrp_snmp_address, 3, {6, 1, 5}}, {VRRP_SNMP_ADDRESS_SCOPE, ASN_INTEGER, RONLY, vrrp_snmp_address, 3, {6, 1, 6}}, {VRRP_SNMP_ADDRESS_IFINDEX, ASN_INTEGER, RONLY, vrrp_snmp_address, 3, {6, 1, 7}}, {VRRP_SNMP_ADDRESS_IFNAME, ASN_OCTET_STR, RONLY, vrrp_snmp_address, 3, {6, 1, 8}}, {VRRP_SNMP_ADDRESS_IFALIAS, ASN_OCTET_STR, RONLY, vrrp_snmp_address, 3, {6, 1, 9}}, {VRRP_SNMP_ADDRESS_ISSET, ASN_INTEGER, RONLY, vrrp_snmp_address, 3, {6, 1, 10}}, {VRRP_SNMP_ADDRESS_ISADVERTISED, ASN_INTEGER, RONLY, vrrp_snmp_address, 3, {6, 1, 11}}, /* vrrpRouteTable */ {VRRP_SNMP_ROUTE_ADDRESSTYPE, ASN_INTEGER, RONLY, vrrp_snmp_route, 3, {7, 1, 2}}, {VRRP_SNMP_ROUTE_DESTINATION, ASN_OCTET_STR, RONLY, vrrp_snmp_route, 3, {7, 1, 3}}, {VRRP_SNMP_ROUTE_DESTINATIONMASK, ASN_UNSIGNED, RONLY, vrrp_snmp_route, 3, {7, 1, 4}}, {VRRP_SNMP_ROUTE_GATEWAY, ASN_OCTET_STR, RONLY, vrrp_snmp_route, 3, {7, 1, 5}}, {VRRP_SNMP_ROUTE_SECONDARYGATEWAY, ASN_OCTET_STR, RONLY, vrrp_snmp_route, 3, {7, 1, 6}}, {VRRP_SNMP_ROUTE_SOURCE, ASN_OCTET_STR, RONLY, vrrp_snmp_route, 3, {7, 1, 7}}, {VRRP_SNMP_ROUTE_METRIC, ASN_UNSIGNED, RONLY, vrrp_snmp_route, 3, {7, 1, 8}}, {VRRP_SNMP_ROUTE_SCOPE, ASN_INTEGER, RONLY, vrrp_snmp_route, 3, {7, 1, 9}}, {VRRP_SNMP_ROUTE_TYPE, ASN_INTEGER, RONLY, vrrp_snmp_route, 3, {7, 1, 10}}, {VRRP_SNMP_ROUTE_IFINDEX, ASN_INTEGER, RONLY, vrrp_snmp_route, 3, {7, 1, 11}}, {VRRP_SNMP_ROUTE_IFNAME, ASN_OCTET_STR, RONLY, vrrp_snmp_route, 3, {7, 1, 12}}, {VRRP_SNMP_ROUTE_ROUTINGTABLE, ASN_UNSIGNED, RONLY, vrrp_snmp_route, 3, {7, 1, 13}}, {VRRP_SNMP_ROUTE_ISSET, ASN_INTEGER, RONLY, vrrp_snmp_route, 3, {7, 1, 14}}, /* vrrpScriptTable */ {VRRP_SNMP_SCRIPT_NAME, ASN_OCTET_STR, RONLY, vrrp_snmp_script, 3, {8, 1, 2}}, {VRRP_SNMP_SCRIPT_COMMAND, ASN_OCTET_STR, RONLY, vrrp_snmp_script, 3, {8, 1, 3}}, {VRRP_SNMP_SCRIPT_INTERVAL, ASN_INTEGER, RONLY, vrrp_snmp_script, 3, {8, 1, 4}}, {VRRP_SNMP_SCRIPT_WEIGHT, ASN_INTEGER, RONLY, vrrp_snmp_script, 3, {8, 1, 5}}, {VRRP_SNMP_SCRIPT_RESULT, ASN_INTEGER, RONLY, vrrp_snmp_script, 3, {8, 1, 6}}, {VRRP_SNMP_SCRIPT_RISE, ASN_UNSIGNED, RONLY, vrrp_snmp_script, 3, {8, 1, 7}}, {VRRP_SNMP_SCRIPT_FALL, ASN_UNSIGNED, RONLY, vrrp_snmp_script, 3, {8, 1, 8}}, }; void vrrp_snmp_agent_init() { snmp_agent_init(vrrp_oid, OID_LENGTH(vrrp_oid), "VRRP", (struct variable *)vrrp_vars, sizeof(struct variable8), sizeof(vrrp_vars)/sizeof(struct variable8)); } void vrrp_snmp_agent_close() { snmp_agent_close(vrrp_oid, OID_LENGTH(vrrp_oid), "VRRP"); } void vrrp_snmp_instance_trap(vrrp_t *vrrp) { /* OID of the notification */ oid notification_oid[] = { VRRP_OID, 9, 0, 2 }; size_t notification_oid_len = OID_LENGTH(notification_oid); /* OID for snmpTrapOID.0 */ oid objid_snmptrap[] = { SNMPTRAP_OID }; size_t objid_snmptrap_len = OID_LENGTH(objid_snmptrap); /* Other OID */ oid name_oid[] = { VRRP_OID, 3, 1, 2 }; size_t name_oid_len = OID_LENGTH(name_oid); oid state_oid[] = { VRRP_OID, 3, 1, 4 }; size_t state_oid_len = OID_LENGTH(state_oid); oid initialstate_oid[] = { VRRP_OID, 3, 1, 5}; size_t initialstate_oid_len = OID_LENGTH(initialstate_oid); oid routerId_oid[] = { KEEPALIVED_OID, 1, 2, 0 }; size_t routerId_oid_len = OID_LENGTH(routerId_oid); netsnmp_variable_list *notification_vars = NULL; static unsigned long state; static unsigned long istate; if (!global_data->enable_traps) return; /* snmpTrapOID */ snmp_varlist_add_variable(¬ification_vars, objid_snmptrap, objid_snmptrap_len, ASN_OBJECT_ID, (u_char *) notification_oid, notification_oid_len * sizeof(oid)); /* vrrpInstanceName */ snmp_varlist_add_variable(¬ification_vars, name_oid, name_oid_len, ASN_OCTET_STR, (u_char *)vrrp->iname, strlen(vrrp->iname)); /* vrrpInstanceState */ state = vrrp_snmp_state(vrrp->state); snmp_varlist_add_variable(¬ification_vars, state_oid, state_oid_len, ASN_INTEGER, (u_char *)&state, sizeof(state)); /* vrrpInstanceInitialState */ istate = vrrp_snmp_state(vrrp->init_state); snmp_varlist_add_variable(¬ification_vars, initialstate_oid, initialstate_oid_len, ASN_INTEGER, (u_char *)&istate, sizeof(istate)); /* routerId */ snmp_varlist_add_variable(¬ification_vars, routerId_oid, routerId_oid_len, ASN_OCTET_STR, (u_char *)global_data->router_id, strlen(global_data->router_id)); log_message(LOG_INFO, "VRRP_Instance(%s): Sending SNMP notification", vrrp->iname); send_v2trap(notification_vars); snmp_free_varbind(notification_vars); } void vrrp_snmp_group_trap(vrrp_sgroup_t *group) { /* OID of the notification */ oid notification_oid[] = { VRRP_OID, 9, 0, 1 }; size_t notification_oid_len = OID_LENGTH(notification_oid); /* OID for snmpTrapOID.0 */ oid objid_snmptrap[] = { SNMPTRAP_OID }; size_t objid_snmptrap_len = OID_LENGTH(objid_snmptrap); /* Other OID */ oid name_oid[] = { VRRP_OID, 1, 1, 2 }; size_t name_oid_len = OID_LENGTH(name_oid); oid state_oid[] = { VRRP_OID, 1, 1, 3 }; size_t state_oid_len = OID_LENGTH(state_oid); oid routerId_oid[] = { KEEPALIVED_OID, 1, 2, 0 }; size_t routerId_oid_len = OID_LENGTH(routerId_oid); netsnmp_variable_list *notification_vars = NULL; static unsigned long state; if (!global_data->enable_traps) return; /* snmpTrapOID */ snmp_varlist_add_variable(¬ification_vars, objid_snmptrap, objid_snmptrap_len, ASN_OBJECT_ID, (u_char *) notification_oid, notification_oid_len * sizeof(oid)); /* vrrpSyncGroupName */ snmp_varlist_add_variable(¬ification_vars, name_oid, name_oid_len, ASN_OCTET_STR, (u_char *)group->gname, strlen(group->gname)); /* vrrpSyncGroupState */ state = vrrp_snmp_state(group->state); snmp_varlist_add_variable(¬ification_vars, state_oid, state_oid_len, ASN_INTEGER, (u_char *)&state, sizeof(state)); /* routerId */ snmp_varlist_add_variable(¬ification_vars, routerId_oid, routerId_oid_len, ASN_OCTET_STR, (u_char *)global_data->router_id, strlen(global_data->router_id)); log_message(LOG_INFO, "VRRP_Group(%s): Sending SNMP notification", group->gname); send_v2trap(notification_vars); snmp_free_varbind(notification_vars); } keepalived-1.2.13/keepalived/vrrp/vrrp_track.c0000664000175000017500000001301112211121152021130 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Interface tracking framework. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ /* local include */ #include "vrrp_track.h" #include "vrrp_if.h" #include "vrrp_data.h" #include "logger.h" #include "memory.h" /* Track interface dump */ void dump_track(void *track_data) { tracked_if_t *tip = track_data; log_message(LOG_INFO, " %s weight %d", IF_NAME(tip->ifp), tip->weight); } void alloc_track(list track_list, vector_t *strvec) { interface_t *ifp = NULL; tracked_if_t *tip = NULL; int weight = 0; char *tracked = vector_slot(strvec, 0); ifp = if_get_by_ifname(tracked); /* Ignoring if no interface found */ if (!ifp) { log_message(LOG_INFO, " %s no match, ignoring...", tracked); return; } if (vector_size(strvec) >= 3 && !strcmp(vector_slot(strvec, 1), "weight")) { weight = atoi(vector_slot(strvec, 2)); if (weight < -254 || weight > 254) { log_message(LOG_INFO, " %s: weight must be between " "[-254..254] inclusive. Ignoring...", tracked); weight = 0; } } tip = (tracked_if_t *) MALLOC(sizeof(tracked_if_t)); tip->ifp = ifp; tip->weight = weight; list_add(track_list, tip); } vrrp_script_t * find_script_by_name(char *name) { element e; vrrp_script_t *scr; if (LIST_ISEMPTY(vrrp_data->vrrp_script)) return NULL; for (e = LIST_HEAD(vrrp_data->vrrp_script); e; ELEMENT_NEXT(e)) { scr = ELEMENT_DATA(e); if (!strcmp(scr->sname, name)) return scr; } return NULL; } /* Track script dump */ void dump_track_script(void *track_data) { tracked_sc_t *tsc = track_data; log_message(LOG_INFO, " %s weight %d", tsc->scr->sname, tsc->weight); } void alloc_track_script(list track_list, vector_t *strvec) { vrrp_script_t *vsc = NULL; tracked_sc_t *tsc = NULL; int weight = 0; char *tracked = vector_slot(strvec, 0); vsc = find_script_by_name(tracked); /* Ignoring if no interface found */ if (!vsc) { log_message(LOG_INFO, " %s no match, ignoring...", tracked); return; } /* default weight */ weight = vsc->weight; if (vector_size(strvec) >= 3 && !strcmp(vector_slot(strvec, 1), "weight")) { weight = atoi(vector_slot(strvec, 2)); if (weight < -254 || weight > 254) { weight = vsc->weight; log_message(LOG_INFO, " %s: weight must be between [-254..254]" " inclusive, ignoring...", tracked); } } tsc = (tracked_sc_t *) MALLOC(sizeof(tracked_sc_t)); tsc->scr = vsc; tsc->weight = weight; vsc->inuse++; list_add(track_list, tsc); } /* Test if all tracked interfaces are either UP or weight-tracked */ int vrrp_tracked_up(list l) { element e; tracked_if_t *tip; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { tip = ELEMENT_DATA(e); if (!tip->weight && !IF_ISUP(tip->ifp)) return 0; } return 1; } /* Log tracked interface down */ void vrrp_log_tracked_down(list l) { element e; tracked_if_t *tip; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { tip = ELEMENT_DATA(e); if (!IF_ISUP(tip->ifp)) log_message(LOG_INFO, "Kernel is reporting: interface %s DOWN", IF_NAME(tip->ifp)); } } /* Returns total weights of all tracked interfaces : * - a positive interface weight adds to the global weight when the * interface is UP. * - a negative interface weight subtracts from the global weight when the * interface is DOWN. * */ int vrrp_tracked_weight(list l) { element e; tracked_if_t *tip; int weight = 0; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { tip = ELEMENT_DATA(e); if (IF_ISUP(tip->ifp)) { if (tip->weight > 0) weight += tip->weight; } else { if (tip->weight < 0) weight += tip->weight; } } return weight; } /* Test if all tracked scripts are either OK or weight-tracked */ int vrrp_script_up(list l) { element e; tracked_sc_t *tsc; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { tsc = ELEMENT_DATA(e); if ((tsc->scr->result == VRRP_SCRIPT_STATUS_DISABLED) || (tsc->scr->result == VRRP_SCRIPT_STATUS_INIT_GOOD)) continue; if (!tsc->weight && tsc->scr->result < tsc->scr->rise) return 0; } return 1; } /* Returns total weights of all tracked scripts : * - a positive weight adds to the global weight when the result is OK * - a negative weight subtracts from the global weight when the result is bad * */ int vrrp_script_weight(list l) { element e; tracked_sc_t *tsc; int weight = 0; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { tsc = ELEMENT_DATA(e); if (tsc->scr->result == VRRP_SCRIPT_STATUS_DISABLED) continue; if (tsc->scr->result >= tsc->scr->rise) { if (tsc->weight > 0) weight += tsc->weight; } else if (tsc->scr->result < tsc->scr->rise) { if (tsc->weight < 0) weight += tsc->weight; } } return weight; } keepalived-1.2.13/keepalived/vrrp/vrrp_parser.c0000644000175000017500000004034312261341653021345 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Configuration file parser/reader. Place into the dynamic * data structure representation the conf file representing * the loadbalanced server pool. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "vrrp_parser.h" #include "vrrp_data.h" #include "vrrp_sync.h" #include "vrrp_index.h" #include "vrrp_if.h" #include "vrrp_vmac.h" #include "vrrp.h" #include "global_data.h" #include "global_parser.h" #include "logger.h" #include "parser.h" #include "memory.h" /* Static addresses handler */ static void static_addresses_handler(vector_t *strvec) { alloc_value_block(strvec, alloc_saddress); } /* Static routes handler */ static void static_routes_handler(vector_t *strvec) { alloc_value_block(strvec, alloc_sroute); } /* VRRP handlers */ static void vrrp_sync_group_handler(vector_t *strvec) { alloc_vrrp_sync_group(vector_slot(strvec, 1)); } static void vrrp_group_handler(vector_t *strvec) { vrrp_sgroup_t *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group); vgroup->iname = read_value_block(); } static void vrrp_gnotify_backup_handler(vector_t *strvec) { vrrp_sgroup_t *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group); vgroup->script_backup = set_value(strvec); vgroup->notify_exec = 1; } static void vrrp_gnotify_master_handler(vector_t *strvec) { vrrp_sgroup_t *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group); vgroup->script_master = set_value(strvec); vgroup->notify_exec = 1; } static void vrrp_gnotify_fault_handler(vector_t *strvec) { vrrp_sgroup_t *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group); vgroup->script_fault = set_value(strvec); vgroup->notify_exec = 1; } static void vrrp_gnotify_handler(vector_t *strvec) { vrrp_sgroup_t *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group); vgroup->script = set_value(strvec); vgroup->notify_exec = 1; } static void vrrp_gsmtp_handler(vector_t *strvec) { vrrp_sgroup_t *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group); vgroup->smtp_alert = 1; } static void vrrp_gglobal_tracking_handler(vector_t *strvec) { vrrp_sgroup_t *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group); vgroup->global_tracking = 1; } static void vrrp_handler(vector_t *strvec) { alloc_vrrp(vector_slot(strvec, 1)); } static void vrrp_vmac_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->vmac_flags |= VRRP_VMAC_FL_SET; if (!vrrp->saddr.ss_family && vrrp->family == AF_INET) inet_ip4tosockaddr(IF_ADDR(vrrp->ifp), &vrrp->saddr); if (vector_size(strvec) == 2) { strncpy(vrrp->vmac_ifname, vector_slot(strvec, 1), IFNAMSIZ - 1); } else if (vrrp->vrid) { snprintf(vrrp->vmac_ifname, IFNAMSIZ, "vrrp.%d", vrrp->vrid); } else { return; } netlink_link_add_vmac(vrrp); } static void vrrp_vmac_xmit_base_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); if (vrrp->vmac_flags & VRRP_VMAC_FL_SET) vrrp->vmac_flags |= VRRP_VMAC_FL_XMITBASE; } static void vrrp_unicast_peer_handler(vector_t *strvec) { alloc_value_block(strvec, alloc_vrrp_unicast_peer); } static void vrrp_native_ipv6_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->family = AF_INET6; if (vrrp->auth_type != VRRP_AUTH_NONE) vrrp->auth_type = VRRP_AUTH_NONE; } static void vrrp_state_handler(vector_t *strvec) { char *str = vector_slot(strvec, 1); vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp_sgroup_t *vgroup = vrrp->sync; if (!strcmp(str, "MASTER")) { vrrp->wantstate = VRRP_STATE_MAST; vrrp->init_state = VRRP_STATE_MAST; } /* set eventual sync group */ if (vgroup) vgroup->state = vrrp->wantstate; } static void vrrp_int_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); char *name = vector_slot(strvec, 1); vrrp->ifp = if_get_by_ifname(name); if (!vrrp->ifp) { log_message(LOG_INFO, "Cant find interface %s for vrrp_instance %s !!!" , name, vrrp->iname); return; } if (vrrp->vmac_flags & VRRP_VMAC_FL_SET) { netlink_link_add_vmac(vrrp); } } static void vrrp_track_int_handler(vector_t *strvec) { alloc_value_block(strvec, alloc_vrrp_track); } static void vrrp_track_scr_handler(vector_t *strvec) { alloc_value_block(strvec, alloc_vrrp_track_script); } static void vrrp_dont_track_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->dont_track_primary = 1; } static void vrrp_srcip_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); struct sockaddr_storage *saddr = &vrrp->saddr; int ret; ret = inet_stosockaddr(vector_slot(strvec, 1), 0, saddr); if (ret < 0) { log_message(LOG_ERR, "Configuration error: VRRP instance[%s] malformed unicast" " src address[%s]. Skipping..." , vrrp->iname, vector_slot(strvec, 1)); return; } if (saddr->ss_family != vrrp->family) { log_message(LOG_ERR, "Configuration error: VRRP instance[%s] and unicast src address" "[%s] MUST be of the same family !!! Skipping..." , vrrp->iname, vector_slot(strvec, 1)); memset(saddr, 0, sizeof(struct sockaddr_storage)); } } static void vrrp_vrid_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->vrid = atoi(vector_slot(strvec, 1)); if (VRRP_IS_BAD_VID(vrrp->vrid)) { log_message(LOG_INFO, "VRRP Error : VRID not valid !"); log_message(LOG_INFO, " must be between 1 & 255. reconfigure !"); } else { alloc_vrrp_bucket(vrrp); if (vrrp->vmac_flags & VRRP_VMAC_FL_SET) { if (strlen(vrrp->vmac_ifname) == 0) snprintf(vrrp->vmac_ifname, IFNAMSIZ, "vrrp.%d", vrrp->vrid); netlink_link_add_vmac(vrrp); } } } static void vrrp_prio_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->effective_priority = vrrp->base_priority = atoi(vector_slot(strvec, 1)); if (VRRP_IS_BAD_PRIORITY(vrrp->base_priority)) { log_message(LOG_INFO, "VRRP Error : Priority not valid !"); log_message(LOG_INFO, " must be between 1 & 255. reconfigure !"); log_message(LOG_INFO, " Using default value : %d\n", VRRP_PRIO_DFL); vrrp->effective_priority = vrrp->base_priority = VRRP_PRIO_DFL; } } static void vrrp_adv_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->adver_int = atoi(vector_slot(strvec, 1)); if (VRRP_IS_BAD_ADVERT_INT(vrrp->adver_int)) { log_message(LOG_INFO, "VRRP Error : Advert interval not valid !"); log_message(LOG_INFO, " must be between less than 1sec."); log_message(LOG_INFO, " Using default value : 1sec"); vrrp->adver_int = 1; } vrrp->adver_int *= TIMER_HZ; } static void vrrp_debug_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->debug = atoi(vector_slot(strvec, 1)); if (VRRP_IS_BAD_DEBUG_INT(vrrp->debug)) { log_message(LOG_INFO, "VRRP Error : Debug interval not valid !"); log_message(LOG_INFO, " must be between 0-4"); vrrp->debug = 0; } } static void vrrp_nopreempt_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->nopreempt = 1; } static void /* backwards compatibility */ vrrp_preempt_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->nopreempt = 0; } static void vrrp_preempt_delay_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->preempt_delay = atoi(vector_slot(strvec, 1)); if (VRRP_IS_BAD_PREEMPT_DELAY(vrrp->preempt_delay)) { log_message(LOG_INFO, "VRRP Error : Preempt_delay not valid !"); log_message(LOG_INFO, " must be between 0-%d", TIMER_MAX_SEC); vrrp->preempt_delay = 0; } vrrp->preempt_delay *= TIMER_HZ; vrrp->preempt_time = timer_add_long(timer_now(), vrrp->preempt_delay); } static void vrrp_notify_backup_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->script_backup = set_value(strvec); vrrp->notify_exec = 1; } static void vrrp_notify_master_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->script_master = set_value(strvec); vrrp->notify_exec = 1; } static void vrrp_notify_fault_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->script_fault = set_value(strvec); vrrp->notify_exec = 1; } static void vrrp_notify_stop_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->script_stop = set_value(strvec); vrrp->notify_exec = 1; } static void vrrp_notify_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->script = set_value(strvec); vrrp->notify_exec = 1; } static void vrrp_smtp_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->smtp_alert = 1; } static void vrrp_lvs_syncd_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->lvs_syncd_if = set_value(strvec); } static void vrrp_garp_delay_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->garp_delay = atoi(vector_slot(strvec, 1)) * TIMER_HZ; if (vrrp->garp_delay < TIMER_HZ) vrrp->garp_delay = TIMER_HZ; } static void vrrp_garp_refresh_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->garp_refresh = atoi(vector_slot(strvec, 1)) * TIMER_HZ; } static void vrrp_auth_type_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); char *str = vector_slot(strvec, 1); if (!strcmp(str, "AH") && vrrp->family == AF_INET) vrrp->auth_type = VRRP_AUTH_AH; else if (!strcmp(str, "PASS") && vrrp->family == AF_INET) vrrp->auth_type = VRRP_AUTH_PASS; } static void vrrp_auth_pass_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); char *str = vector_slot(strvec, 1); int max_size = sizeof (vrrp->auth_data); int str_len = strlen(str); if (str_len > max_size) { str_len = max_size; log_message(LOG_INFO, "Truncating auth_pass to %d characters", max_size); } memset(vrrp->auth_data, 0, max_size); memcpy(vrrp->auth_data, str, str_len); } static void vrrp_vip_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); char *buf; char *str = NULL; vector_t *vec = NULL; int nbvip = 0; buf = (char *) MALLOC(MAXBUF); while (read_line(buf, MAXBUF)) { vec = alloc_strvec(buf); if (vec) { str = vector_slot(vec, 0); if (!strcmp(str, EOB)) { free_strvec(vec); break; } if (vector_size(vec)) { nbvip++; if (nbvip > VRRP_MAX_VIP) { log_message(LOG_INFO, "VRRP_Instance(%s) " "trunc to the first %d VIPs.", vrrp->iname, VRRP_MAX_VIP); log_message(LOG_INFO, " => Declare others VIPs into" " the excluded vip block"); } else alloc_vrrp_vip(vec); } free_strvec(vec); } memset(buf, 0, MAXBUF); } FREE(buf); } static void vrrp_evip_handler(vector_t *strvec) { alloc_value_block(strvec, alloc_vrrp_evip); } static void vrrp_vroutes_handler(vector_t *strvec) { alloc_value_block(strvec, alloc_vrrp_vroute); } static void vrrp_script_handler(vector_t *strvec) { alloc_vrrp_script(vector_slot(strvec, 1)); } static void vrrp_vscript_script_handler(vector_t *strvec) { vrrp_script_t *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script); vscript->script = set_value(strvec); } static void vrrp_vscript_interval_handler(vector_t *strvec) { vrrp_script_t *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script); vscript->interval = atoi(vector_slot(strvec, 1)) * TIMER_HZ; if (vscript->interval < TIMER_HZ) vscript->interval = TIMER_HZ; } static void vrrp_vscript_timeout_handler(vector_t *strvec) { vrrp_script_t *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script); vscript->timeout = atoi(vector_slot(strvec, 1)) * TIMER_HZ; if (vscript->timeout < TIMER_HZ) vscript->timeout = TIMER_HZ; } static void vrrp_vscript_weight_handler(vector_t *strvec) { vrrp_script_t *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script); vscript->weight = atoi(vector_slot(strvec, 1)); } static void vrrp_vscript_rise_handler(vector_t *strvec) { vrrp_script_t *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script); vscript->rise = atoi(vector_slot(strvec, 1)); if (vscript->rise < 1) vscript->rise = 1; } static void vrrp_vscript_fall_handler(vector_t *strvec) { vrrp_script_t *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script); vscript->fall = atoi(vector_slot(strvec, 1)); if (vscript->fall < 1) vscript->fall = 1; } vector_t * vrrp_init_keywords(void) { /* global definitions mapping */ global_init_keywords(); /* Static routes mapping */ install_keyword_root("static_ipaddress", &static_addresses_handler); install_keyword_root("static_routes", &static_routes_handler); /* VRRP Instance mapping */ install_keyword_root("vrrp_sync_group", &vrrp_sync_group_handler); install_keyword("group", &vrrp_group_handler); install_keyword("notify_backup", &vrrp_gnotify_backup_handler); install_keyword("notify_master", &vrrp_gnotify_master_handler); install_keyword("notify_fault", &vrrp_gnotify_fault_handler); install_keyword("notify", &vrrp_gnotify_handler); install_keyword("smtp_alert", &vrrp_gsmtp_handler); install_keyword("global_tracking", &vrrp_gglobal_tracking_handler); install_keyword_root("vrrp_instance", &vrrp_handler); install_keyword("use_vmac", &vrrp_vmac_handler); install_keyword("vmac_xmit_base", &vrrp_vmac_xmit_base_handler); install_keyword("unicast_peer", &vrrp_unicast_peer_handler); install_keyword("native_ipv6", &vrrp_native_ipv6_handler); install_keyword("state", &vrrp_state_handler); install_keyword("interface", &vrrp_int_handler); install_keyword("dont_track_primary", &vrrp_dont_track_handler); install_keyword("track_interface", &vrrp_track_int_handler); install_keyword("track_script", &vrrp_track_scr_handler); install_keyword("mcast_src_ip", &vrrp_srcip_handler); install_keyword("unicast_src_ip", &vrrp_srcip_handler); install_keyword("virtual_router_id", &vrrp_vrid_handler); install_keyword("priority", &vrrp_prio_handler); install_keyword("advert_int", &vrrp_adv_handler); install_keyword("virtual_ipaddress", &vrrp_vip_handler); install_keyword("virtual_ipaddress_excluded", &vrrp_evip_handler); install_keyword("virtual_routes", &vrrp_vroutes_handler); install_keyword("preempt", &vrrp_preempt_handler); install_keyword("nopreempt", &vrrp_nopreempt_handler); install_keyword("preempt_delay", &vrrp_preempt_delay_handler); install_keyword("debug", &vrrp_debug_handler); install_keyword("notify_backup", &vrrp_notify_backup_handler); install_keyword("notify_master", &vrrp_notify_master_handler); install_keyword("notify_fault", &vrrp_notify_fault_handler); install_keyword("notify_stop", &vrrp_notify_stop_handler); install_keyword("notify", &vrrp_notify_handler); install_keyword("smtp_alert", &vrrp_smtp_handler); install_keyword("lvs_sync_daemon_interface", &vrrp_lvs_syncd_handler); install_keyword("garp_master_delay", &vrrp_garp_delay_handler); install_keyword("garp_master_refresh", &vrrp_garp_refresh_handler); install_keyword("authentication", NULL); install_sublevel(); install_keyword("auth_type", &vrrp_auth_type_handler); install_keyword("auth_pass", &vrrp_auth_pass_handler); install_sublevel_end(); install_keyword_root("vrrp_script", &vrrp_script_handler); install_keyword("script", &vrrp_vscript_script_handler); install_keyword("interval", &vrrp_vscript_interval_handler); install_keyword("timeout", &vrrp_vscript_timeout_handler); install_keyword("weight", &vrrp_vscript_weight_handler); install_keyword("rise", &vrrp_vscript_rise_handler); install_keyword("fall", &vrrp_vscript_fall_handler); return keywords; } keepalived-1.2.13/keepalived/vrrp/vrrp_vmac.c0000644000175000017500000001551012334072037020773 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: NETLINK VMAC address manipulation. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ /* local include */ #include "vrrp_vmac.h" #include "vrrp_netlink.h" #include "vrrp_data.h" #include "logger.h" #include "memory.h" #include "utils.h" #include "parser.h" /* private matter */ static const char *ll_kind = "macvlan"; #ifdef _HAVE_VRRP_VMAC_ /* Link layer handling */ static int netlink_link_setlladdr(vrrp_t *vrrp) { int status = 1; u_char ll_addr[ETH_ALEN] = {0x00, 0x00, 0x5e, 0x00, 0x01, vrrp->vrid}; struct { struct nlmsghdr n; struct ifinfomsg ifi; char buf[256]; } req; memset(&req, 0, sizeof (req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_NEWLINK; req.ifi.ifi_family = AF_INET; req.ifi.ifi_index = IF_INDEX(vrrp->ifp); addattr_l(&req.n, sizeof(req), IFLA_ADDRESS, ll_addr, ETH_ALEN); if (netlink_talk(&nl_cmd, &req.n) < 0) status = -1; else memcpy(vrrp->ifp->hw_addr, ll_addr, ETH_ALEN); return status; } static int netlink_link_setmode(vrrp_t *vrrp) { int status = 1; struct { struct nlmsghdr n; struct ifinfomsg ifi; char buf[256]; } req; struct rtattr *linkinfo; struct rtattr *data; memset(&req, 0, sizeof (req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_NEWLINK; req.ifi.ifi_family = AF_INET; req.ifi.ifi_index = IF_INDEX(vrrp->ifp); linkinfo = NLMSG_TAIL(&req.n); addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, (void *) ll_kind, strlen(ll_kind)); data = NLMSG_TAIL(&req.n); addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); /* * In private mode, macvlan will receive frames with same MAC addr * as configured on the interface. */ addattr32(&req.n, sizeof(req), IFLA_MACVLAN_MODE, MACVLAN_MODE_PRIVATE); data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; if (netlink_talk(&nl_cmd, &req.n) < 0) status = -1; return status; } static int netlink_link_up(vrrp_t *vrrp) { int status = 1; struct { struct nlmsghdr n; struct ifinfomsg ifi; char buf[256]; } req; memset(&req, 0, sizeof (req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_NEWLINK; req.ifi.ifi_family = AF_UNSPEC; req.ifi.ifi_index = IF_INDEX(vrrp->ifp); req.ifi.ifi_change |= IFF_UP; req.ifi.ifi_flags |= IFF_UP; if (netlink_talk(&nl_cmd, &req.n) < 0) status = -1; return status; } #endif int netlink_link_add_vmac(vrrp_t *vrrp) { #ifdef _HAVE_VRRP_VMAC_ struct rtattr *linkinfo; unsigned int base_ifindex; interface_t *ifp; char ifname[IFNAMSIZ]; struct { struct nlmsghdr n; struct ifinfomsg ifi; char buf[256]; } req; if (!vrrp->ifp || vrrp->vmac_flags & VRRP_VMAC_FL_UP || !vrrp->vrid) return -1; memset(&req, 0, sizeof (req)); memset(ifname, 0, IFNAMSIZ); strncpy(ifname, vrrp->vmac_ifname, IFNAMSIZ - 1); /* * Check to see if this vmac interface was created * by a previous instance. */ if (reload && (ifp = if_get_by_ifname(ifname))) { /* (re)set VMAC properties (if deleted on reload) */ ifp->base_ifindex = vrrp->ifp->ifindex; ifp->vmac = 1; ifp->flags = vrrp->ifp->flags; /* Copy base interface flags */ vrrp->ifp = ifp; /* Save ifindex for use on delete */ vrrp->vmac_ifindex = IF_INDEX(vrrp->ifp); vrrp->vmac_flags |= VRRP_VMAC_FL_UP; return 1; } req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; req.n.nlmsg_type = RTM_NEWLINK; req.ifi.ifi_family = AF_INET; /* macvlan settings */ linkinfo = NLMSG_TAIL(&req.n); addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, (void *)ll_kind, strlen(ll_kind)); linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; addattr_l(&req.n, sizeof(req), IFLA_LINK, &IF_INDEX(vrrp->ifp), sizeof(uint32_t)); addattr_l(&req.n, sizeof(req), IFLA_IFNAME, ifname, strlen(ifname)); if (netlink_talk(&nl_cmd, &req.n) < 0) { log_message(LOG_INFO, "vmac: Error creating VMAC interface %s for vrrp_instance %s!!!" , ifname, vrrp->iname); return -1; } log_message(LOG_INFO, "vmac: Success creating VMAC interface %s for vrrp_instance %s" , ifname, vrrp->iname); /* * Update interface queue and vrrp instance interface binding. * bring it UP ! */ netlink_interface_lookup(); ifp = if_get_by_ifname(ifname); if (!ifp) return -1; base_ifindex = vrrp->ifp->ifindex; ifp->flags = vrrp->ifp->flags; /* Copy base interface flags */ vrrp->ifp = ifp; vrrp->ifp->base_ifindex = base_ifindex; vrrp->ifp->vmac = 1; vrrp->vmac_ifindex = IF_INDEX(vrrp->ifp); /* For use on delete */ vrrp->vmac_flags |= VRRP_VMAC_FL_UP; netlink_link_setlladdr(vrrp); netlink_link_up(vrrp); /* * By default MACVLAN interface are in VEPA mode which filters * out received packets whose MAC source address matches that * of the MACVLAN interface. Setting MACVLAN interface in private * mode will not filter based on source MAC address. */ netlink_link_setmode(vrrp); #endif return 1; } int netlink_link_del_vmac(vrrp_t *vrrp) { int status = 1; #ifdef _HAVE_VRRP_VMAC_ struct { struct nlmsghdr n; struct ifinfomsg ifi; char buf[256]; } req; if (!vrrp->ifp) return -1; memset(&req, 0, sizeof (req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_DELLINK; req.ifi.ifi_family = AF_INET; req.ifi.ifi_index = vrrp->vmac_ifindex; if (netlink_talk(&nl_cmd, &req.n) < 0) { log_message(LOG_INFO, "vmac: Error removing VMAC interface %s for vrrp_instance %s!!!" , vrrp->vmac_ifname, vrrp->iname); status = -1; } log_message(LOG_INFO, "vmac: Success removing VMAC interface %s for vrrp_instance %s" , vrrp->vmac_ifname, vrrp->iname); #endif return status; } keepalived-1.2.13/keepalived/vrrp/vrrp_scheduler.c0000644000175000017500000007132112334144506022026 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Sheduling framework for vrrp code. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "vrrp_scheduler.h" #include "vrrp_ipsecah.h" #include "vrrp_if.h" #include "vrrp_vmac.h" #include "vrrp.h" #include "vrrp_sync.h" #include "vrrp_notify.h" #include "vrrp_netlink.h" #include "vrrp_data.h" #include "vrrp_index.h" #include "ipvswrapper.h" #include "memory.h" #include "notify.h" #include "list.h" #include "logger.h" #include "main.h" #include "smtp.h" #include "signals.h" #ifdef _WITH_SNMP_ #include "vrrp_snmp.h" #endif /* VRRP FSM (Finite State Machine) design. * * The state transition diagram implemented is : * * +---------------+ * +----------------| |----------------+ * | | Fault | | * | +------------>| |<------------+ | * | | +---------------+ | | * | | | | | * | | V | | * | | +---------------+ | | * | | +--------->| |<---------+ | | * | | | | Initialize | | | | * | | | +-------| |-------+ | | | * | | | | +---------------+ | | | | * | | | | | | | | * V | | V V | | V * +---------------+ +---------------+ * | |---------------------->| | * | Master | | Backup | * | |<----------------------| | * +---------------+ +---------------+ */ static void vrrp_backup(vrrp_t *, char *, int); static void vrrp_leave_master(vrrp_t *, char *, int); static void vrrp_leave_fault(vrrp_t *, char *, int); static void vrrp_become_master(vrrp_t *, char *, int); static void vrrp_goto_master(vrrp_t *); static void vrrp_master(vrrp_t *); static void vrrp_fault(vrrp_t *); static int vrrp_update_priority(thread_t * thread); static int vrrp_script_child_timeout_thread(thread_t * thread); static int vrrp_script_child_thread(thread_t * thread); static int vrrp_script_thread(thread_t * thread); struct { void (*read) (vrrp_t *, char *, int); void (*read_to) (vrrp_t *); } VRRP_FSM[VRRP_MAX_FSM_STATE + 1] = { /* Stream Read Handlers | Stream Read_to handlers * *------------------------------+------------------------------*/ {NULL, NULL}, {vrrp_backup, vrrp_goto_master}, /* BACKUP */ {vrrp_leave_master, vrrp_master}, /* MASTER */ {vrrp_leave_fault, vrrp_fault}, /* FAULT */ {vrrp_become_master, vrrp_goto_master} /* GOTO_MASTER */ }; /* VRRP TSM (Transition State Matrix) design. * * Introducing the Synchronization extension to VRRP * protocol, introduce the need for a transition machinery. * This mecanism can be designed using a diagonal matrix. * We call this matrix the VRRP TSM: * * \ E | B | M | F | * S \ | | | | * ------+-----+-----+-----+ Legend: * B | x 1 2 | B: VRRP BACKUP state * ------+ | M: VRRP MASTER state * M | 3 x 4 | F: VRRP FAULT state * ------+ | S: VRRP start state (before transition) * F | 5 6 x | E: VRRP end state (after transition) * ------+-----------------+ [1..6]: Handler functions. * * So we have have to implement n(n-1) handlers in order to deal with * all transitions possible. This matrix defines the maximum handlers * to implement for having the most time optimized transition machine. * For example: * . The handler (1) will sync all the BACKUP VRRP instances of a * group to MASTER state => we will call it vrrp_sync_master. * .... and so on for all other state .... * * This matrix is the strict implementation way. For readability and * performance we have implemented some handlers directly into the VRRP * FSM. For instance the handlers (5) & (6) are directly into the VRRP * FSM since it will speed up convergence to init state. * Additionnaly, we have implemented some other handlers into the matrix * in order to speed up group synchronization takeover. For instance * transitions : * o B->B: To catch wantstate MASTER transition to force sync group * to this transition state too. * o F->F: To speed up FAULT state transition if group is not already * synced to FAULT state. */ struct { void (*handler) (vrrp_t *); } VRRP_TSM[VRRP_MAX_TSM_STATE + 1][VRRP_MAX_TSM_STATE + 1] = { { {NULL}, {NULL}, {NULL}, {NULL} }, { {NULL}, {vrrp_sync_master_election}, {vrrp_sync_master}, {vrrp_sync_fault} }, { {NULL}, {vrrp_sync_backup}, {vrrp_sync_master}, {vrrp_sync_fault} }, { {NULL}, {vrrp_sync_backup}, {vrrp_sync_master}, {vrrp_sync_fault} } }; /* SMTP alert notifier */ static void vrrp_smtp_notifier(vrrp_t * vrrp) { if (vrrp->smtp_alert) { if (vrrp->state == VRRP_STATE_MAST) smtp_alert(NULL, vrrp, NULL, "Entering MASTER state", "=> VRRP Instance is now owning VRRP VIPs <="); if (vrrp->state == VRRP_STATE_BACK) smtp_alert(NULL, vrrp, NULL, "Entering BACKUP state", "=> VRRP Instance is nolonger owning VRRP VIPs <="); } } /* Log interface message */ static void vrrp_log_int_down(vrrp_t *vrrp) { if (!IF_ISUP(vrrp->ifp)) log_message(LOG_INFO, "Kernel is reporting: interface %s DOWN", IF_NAME(vrrp->ifp)); if (!LIST_ISEMPTY(vrrp->track_ifp)) vrrp_log_tracked_down(vrrp->track_ifp); } static void vrrp_log_int_up(vrrp_t *vrrp) { if (IF_ISUP(vrrp->ifp)) log_message(LOG_INFO, "Kernel is reporting: interface %s UP", IF_NAME(vrrp->ifp)); if (!LIST_ISEMPTY(vrrp->track_ifp)) log_message(LOG_INFO, "Kernel is reporting: tracked interface are UP"); } /* * Initialize state handling * --rfc2338.6.4.1 */ static void vrrp_init_state(list l) { vrrp_t *vrrp; vrrp_sgroup_t *vgroup; element e; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); /* In case of VRRP SYNC, we have to carefully check that we are * not running floating priorities on any VRRP instance. */ if (vrrp->sync && !vrrp->sync->global_tracking) { element e2; tracked_sc_t *sc; tracked_if_t *tip; int warning = 0; if (!LIST_ISEMPTY(vrrp->track_ifp)) { for (e2 = LIST_HEAD(vrrp->track_ifp); e2; ELEMENT_NEXT(e2)) { tip = ELEMENT_DATA(e2); if (tip->weight) { tip->weight = 0; warning++; } } } if (!LIST_ISEMPTY(vrrp->track_script)) { for (e2 = LIST_HEAD(vrrp->track_script); e2; ELEMENT_NEXT(e2)) { sc = ELEMENT_DATA(e2); if (sc->weight) { sc->scr->inuse--; warning++; } } } if (warning > 0) { log_message(LOG_INFO, "VRRP_Instance(%s) : ignoring " "tracked script with weights due to SYNC group", vrrp->iname); } } else { /* Register new priority update thread */ thread_add_timer(master, vrrp_update_priority, vrrp, vrrp->adver_int); } if (vrrp->base_priority == VRRP_PRIO_OWNER || vrrp->wantstate == VRRP_STATE_MAST) { #ifdef _HAVE_IPVS_SYNCD_ /* Check if sync daemon handling is needed */ if (vrrp->lvs_syncd_if) ipvs_syncd_cmd(IPVS_STARTDAEMON, vrrp->lvs_syncd_if, IPVS_MASTER, vrrp->vrid); #endif vrrp->state = VRRP_STATE_GOTO_MASTER; } else { vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp); #ifdef _HAVE_IPVS_SYNCD_ /* Check if sync daemon handling is needed */ if (vrrp->lvs_syncd_if) ipvs_syncd_cmd(IPVS_STARTDAEMON, vrrp->lvs_syncd_if, IPVS_BACKUP, vrrp->vrid); #endif log_message(LOG_INFO, "VRRP_Instance(%s) Entering BACKUP STATE", vrrp->iname); /* Set BACKUP state */ vrrp_restore_interface(vrrp, 0); vrrp->state = VRRP_STATE_BACK; vrrp_smtp_notifier(vrrp); notify_instance_exec(vrrp, VRRP_STATE_BACK); #ifdef _WITH_SNMP_ vrrp_snmp_instance_trap(vrrp); #endif /* Init group if needed */ if ((vgroup = vrrp->sync)) { if (GROUP_STATE(vgroup) != VRRP_STATE_BACK) { vgroup->state = VRRP_STATE_BACK; vrrp_sync_smtp_notifier(vgroup); notify_group_exec(vgroup, VRRP_STATE_BACK); #ifdef _WITH_SNMP_ vrrp_snmp_group_trap(vgroup); #endif } } } } } static void vrrp_init_sands(list l) { vrrp_t *vrrp; element e; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); vrrp_init_instance_sands(vrrp); } } /* if run after vrrp_init_state(), it will be able to detect scripts that * have been disabled because of a sync group and will avoid to start them. */ static void vrrp_init_script(list l) { vrrp_script_t *vscript; element e; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vscript = ELEMENT_DATA(e); if (vscript->inuse == 0) vscript->result = VRRP_SCRIPT_STATUS_DISABLED; if (vscript->result == VRRP_SCRIPT_STATUS_INIT) { vscript->result = vscript->rise - 1; /* one success is enough */ thread_add_event(master, vrrp_script_thread, vscript, vscript->interval); } else if (vscript->result == VRRP_SCRIPT_STATUS_INIT_GOOD) { vscript->result = vscript->rise; /* one failure is enough */ thread_add_event(master, vrrp_script_thread, vscript, vscript->interval); } } } /* Timer functions */ static timeval_t vrrp_compute_timer(const int fd) { vrrp_t *vrrp; element e; list l = &vrrp_data->vrrp_index_fd[fd%1024 + 1]; timeval_t timer; /* Multiple instances on the same interface */ timer_reset(timer); for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); if (timer_cmp(vrrp->sands, timer) < 0 || timer_isnull(timer)) timer = timer_dup(vrrp->sands); } return timer; } static long vrrp_timer_fd(const int fd) { timeval_t timer, vrrp_timer; long vrrp_long; timer = vrrp_compute_timer(fd); vrrp_timer = timer_sub(timer, time_now); vrrp_long = timer_long(vrrp_timer); return (vrrp_long < 0) ? TIMER_MAX_SEC : vrrp_long; } static int vrrp_timer_vrid_timeout(const int fd) { vrrp_t *vrrp; element e; list l = &vrrp_data->vrrp_index_fd[fd%1024 + 1]; timeval_t timer; int vrid = 0; /* Multiple instances on the same interface */ timer_reset(timer); for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); if (timer_cmp(vrrp->sands, timer) < 0 || timer_isnull(timer)) { timer = timer_dup(vrrp->sands); vrid = vrrp->vrid; } } return vrid; } /* Thread functions */ static void vrrp_register_workers(list l) { sock_t *sock; timeval_t timer; long vrrp_timer = 0; element e; /* Init compute timer */ memset(&timer, 0, sizeof (struct timeval)); /* Init the VRRP instances state */ vrrp_init_state(vrrp_data->vrrp); /* Init VRRP instances sands */ vrrp_init_sands(vrrp_data->vrrp); /* Init VRRP tracking scripts */ if (!LIST_ISEMPTY(vrrp_data->vrrp_script)) vrrp_init_script(vrrp_data->vrrp_script); /* Register VRRP workers threads */ for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { sock = ELEMENT_DATA(e); /* jump to asynchronous handling */ vrrp_timer = vrrp_timer_fd(sock->fd_in); /* Register a timer thread if interface is shut */ if (sock->fd_in == -1) sock->thread = thread_add_timer(master, vrrp_read_dispatcher_thread, sock, vrrp_timer); else sock->thread = thread_add_read(master, vrrp_read_dispatcher_thread, sock, sock->fd_in, vrrp_timer); } } /* VRRP dispatcher functions */ static int already_exist_sock(list l, sa_family_t family, int proto, int ifindex, int unicast) { sock_t *sock; element e; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { sock = ELEMENT_DATA(e); if ((sock->family == family) && (sock->proto == proto) && (sock->ifindex == ifindex) && (sock->unicast == unicast)) return 1; } return 0; } void alloc_sock(sa_family_t family, list l, int proto, int ifindex, int unicast) { sock_t *new; new = (sock_t *) MALLOC(sizeof (sock_t)); new->family = family; new->proto = proto; new->ifindex = ifindex; new->unicast = unicast; list_add(l, new); } static void vrrp_create_sockpool(list l) { vrrp_t *vrrp; list p = vrrp_data->vrrp; element e; int ifindex, proto, unicast; for (e = LIST_HEAD(p); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); ifindex = (vrrp->vmac_flags & VRRP_VMAC_FL_XMITBASE) ? IF_BASE_INDEX(vrrp->ifp) : IF_INDEX(vrrp->ifp); unicast = !LIST_ISEMPTY(vrrp->unicast_peer); if (vrrp->auth_type == VRRP_AUTH_AH) proto = IPPROTO_IPSEC_AH; else proto = IPPROTO_VRRP; /* add the vrrp element if not exist */ if (!already_exist_sock(l, vrrp->family, proto, ifindex, unicast)) alloc_sock(vrrp->family, l, proto, ifindex, unicast); } } static void vrrp_open_sockpool(list l) { sock_t *sock; element e; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { sock = ELEMENT_DATA(e); sock->fd_in = open_vrrp_socket(sock->family, sock->proto, sock->ifindex, sock->unicast); if (sock->fd_in == -1) sock->fd_out = -1; else sock->fd_out = open_vrrp_send_socket(sock->family, sock->proto, sock->ifindex, sock->unicast); } } static void vrrp_set_fds(list l) { sock_t *sock; vrrp_t *vrrp; list p = vrrp_data->vrrp; element e_sock; element e_vrrp; int proto, ifindex, unicast; for (e_sock = LIST_HEAD(l); e_sock; ELEMENT_NEXT(e_sock)) { sock = ELEMENT_DATA(e_sock); for (e_vrrp = LIST_HEAD(p); e_vrrp; ELEMENT_NEXT(e_vrrp)) { vrrp = ELEMENT_DATA(e_vrrp); ifindex = (vrrp->vmac_flags & VRRP_VMAC_FL_XMITBASE) ? IF_BASE_INDEX(vrrp->ifp) : IF_INDEX(vrrp->ifp); unicast = !LIST_ISEMPTY(vrrp->unicast_peer); if (vrrp->auth_type == VRRP_AUTH_AH) proto = IPPROTO_IPSEC_AH; else proto = IPPROTO_VRRP; if ((sock->ifindex == ifindex) && (sock->proto == proto) && (sock->unicast == unicast)) { vrrp->fd_in = sock->fd_in; vrrp->fd_out = sock->fd_out; /* append to hash index */ alloc_vrrp_fd_bucket(vrrp); } } } } /* * We create & allocate a socket pool here. The soft design * can be sum up by the following sketch : * * fd1 fd2 fd3 fd4 fdi fdi+1 * -----\__/--------\__/---........---\__/--- * | ETH0 | | ETH1 | | ETHn | * +------+ +------+ +------+ * * Here we have n physical NIC. Each NIC own a maximum of 2 fds. * (one for VRRP the other for IPSEC_AH). All our VRRP instances * are multiplexed through this fds. So our design can handle 2*n * multiplexing points. */ int vrrp_dispatcher_init(thread_t * thread) { /* create the VRRP socket pool list */ vrrp_create_sockpool(vrrp_data->vrrp_socket_pool); /* open the VRRP socket pool */ vrrp_open_sockpool(vrrp_data->vrrp_socket_pool); /* set VRRP instance fds to sockpool */ vrrp_set_fds(vrrp_data->vrrp_socket_pool); /* register read dispatcher worker thread */ vrrp_register_workers(vrrp_data->vrrp_socket_pool); /* Dump socket pool */ if (debug & 32) dump_list(vrrp_data->vrrp_socket_pool); return 1; } void vrrp_dispatcher_release(vrrp_data_t *data) { free_list(data->vrrp_socket_pool); } static void vrrp_backup(vrrp_t * vrrp, char *buffer, int len) { struct iphdr *iph; ipsec_ah_t *ah; if (vrrp->family == AF_INET) { iph = (struct iphdr *) buffer; if (iph->protocol == IPPROTO_IPSEC_AH) { ah = (ipsec_ah_t *) (buffer + sizeof (struct iphdr)); if (ntohl(ah->seq_number) >= vrrp->ipsecah_counter->seq_number) vrrp->ipsecah_counter->cycle = 0; } } vrrp_state_backup(vrrp, buffer, len); } static void vrrp_become_master(vrrp_t * vrrp, char *buffer, int len) { struct iphdr *iph; ipsec_ah_t *ah; if (vrrp->family == AF_INET) { iph = (struct iphdr *) buffer; /* * If we are in IPSEC AH mode, we must be sync * with the remote IPSEC AH VRRP instance counter. */ if (iph->protocol == IPPROTO_IPSEC_AH) { log_message(LOG_INFO, "VRRP_Instance(%s) IPSEC-AH : seq_num sync", vrrp->iname); ah = (ipsec_ah_t *) (buffer + sizeof (struct iphdr)); vrrp->ipsecah_counter->seq_number = ntohl(ah->seq_number) + 1; vrrp->ipsecah_counter->cycle = 0; } } /* Then jump to master state */ vrrp->wantstate = VRRP_STATE_MAST; vrrp_state_goto_master(vrrp); } static void vrrp_leave_master(vrrp_t * vrrp, char *buffer, int len) { if (!VRRP_ISUP(vrrp)) { vrrp_log_int_down(vrrp); vrrp->wantstate = VRRP_STATE_GOTO_FAULT; vrrp_state_leave_master(vrrp); } else if (vrrp_state_master_rx(vrrp, buffer, len)) { vrrp_state_leave_master(vrrp); vrrp_smtp_notifier(vrrp); } } static void vrrp_ah_sync(vrrp_t *vrrp) { /* * Transition to BACKUP state for AH * seq number synchronization. */ log_message(LOG_INFO, "VRRP_Instance(%s) in FAULT state jump to AH sync", vrrp->iname); vrrp->wantstate = VRRP_STATE_BACK; vrrp_state_leave_master(vrrp); } static void vrrp_leave_fault(vrrp_t * vrrp, char *buffer, int len) { if (!VRRP_ISUP(vrrp)) return; if (vrrp_state_fault_rx(vrrp, buffer, len)) { if (vrrp->sync) { if (vrrp_sync_leave_fault(vrrp)) { log_message(LOG_INFO, "VRRP_Instance(%s) prio is higher than received advert", vrrp->iname); vrrp_become_master(vrrp, buffer, len); } } else { log_message(LOG_INFO, "VRRP_Instance(%s) prio is higher than received advert", vrrp->iname); vrrp_become_master(vrrp, buffer, len); } } else { if (vrrp->sync) { if (vrrp_sync_leave_fault(vrrp)) { log_message(LOG_INFO, "VRRP_Instance(%s) Entering BACKUP STATE", vrrp->iname); vrrp->state = VRRP_STATE_BACK; vrrp_smtp_notifier(vrrp); notify_instance_exec(vrrp, VRRP_STATE_BACK); #ifdef _WITH_SNMP_ vrrp_snmp_instance_trap(vrrp); #endif } } else { log_message(LOG_INFO, "VRRP_Instance(%s) Entering BACKUP STATE", vrrp->iname); vrrp->state = VRRP_STATE_BACK; vrrp_smtp_notifier(vrrp); notify_instance_exec(vrrp, VRRP_STATE_BACK); #ifdef _WITH_SNMP_ vrrp_snmp_instance_trap(vrrp); #endif } } } static void vrrp_goto_master(vrrp_t * vrrp) { if (!VRRP_ISUP(vrrp)) { vrrp_log_int_down(vrrp); log_message(LOG_INFO, "VRRP_Instance(%s) Now in FAULT state", vrrp->iname); if (vrrp->state != VRRP_STATE_FAULT) notify_instance_exec(vrrp, VRRP_STATE_FAULT); vrrp->state = VRRP_STATE_FAULT; vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp); notify_instance_exec(vrrp, VRRP_STATE_FAULT); #ifdef _WITH_SNMP_ vrrp_snmp_instance_trap(vrrp); #endif } else { /* If becoming MASTER in IPSEC AH AUTH, we reset the anti-replay */ if (vrrp->ipsecah_counter->cycle) { vrrp->ipsecah_counter->cycle = 0; vrrp->ipsecah_counter->seq_number = 0; } /* handle master state transition */ vrrp->wantstate = VRRP_STATE_MAST; vrrp_state_goto_master(vrrp); } } /* Delayed gratuitous ARP thread */ int vrrp_gratuitous_arp_thread(thread_t * thread) { vrrp_t *vrrp = THREAD_ARG(thread); /* Simply broadcast the gratuitous ARP */ vrrp_send_link_update(vrrp); return 0; } /* Update VRRP effective priority based on multiple checkers. * This is a thread which is executed every adver_int. */ static int vrrp_update_priority(thread_t * thread) { vrrp_t *vrrp = THREAD_ARG(thread); int prio_offset, new_prio; /* compute prio_offset right here */ prio_offset = 0; /* Now we will sum the weights of all interfaces which are tracked. */ if ((!vrrp->sync || vrrp->sync->global_tracking) && !LIST_ISEMPTY(vrrp->track_ifp)) prio_offset += vrrp_tracked_weight(vrrp->track_ifp); /* Now we will sum the weights of all scripts which are tracked. */ if ((!vrrp->sync || vrrp->sync->global_tracking) && !LIST_ISEMPTY(vrrp->track_script)) prio_offset += vrrp_script_weight(vrrp->track_script); if (vrrp->base_priority == VRRP_PRIO_OWNER) { /* we will not run a PRIO_OWNER into a non-PRIO_OWNER */ vrrp->effective_priority = VRRP_PRIO_OWNER; } else { /* WARNING! we must compute new_prio on a signed int in order to detect overflows and avoid wrapping. */ new_prio = vrrp->base_priority + prio_offset; if (new_prio < 1) new_prio = 1; else if (new_prio > 254) new_prio = 254; vrrp->effective_priority = new_prio; } /* Register next priority update thread */ thread_add_timer(master, vrrp_update_priority, vrrp, vrrp->adver_int); return 0; } static void vrrp_master(vrrp_t * vrrp) { /* Check if interface we are running on is UP */ if (vrrp->wantstate != VRRP_STATE_GOTO_FAULT) { if (!VRRP_ISUP(vrrp)) { vrrp_log_int_down(vrrp); vrrp->wantstate = VRRP_STATE_GOTO_FAULT; } } /* Then perform the state transition */ if (vrrp->wantstate == VRRP_STATE_GOTO_FAULT || vrrp->wantstate == VRRP_STATE_BACK || vrrp->ipsecah_counter->cycle) { vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp); /* handle backup state transition */ vrrp_state_leave_master(vrrp); if (vrrp->state == VRRP_STATE_BACK) log_message(LOG_INFO, "VRRP_Instance(%s) Now in BACKUP state", vrrp->iname); if (vrrp->state == VRRP_STATE_FAULT) log_message(LOG_INFO, "VRRP_Instance(%s) Now in FAULT state", vrrp->iname); } else if (vrrp->state == VRRP_STATE_MAST) { /* * Send the VRRP advert. * If we catch the master transition * <=> vrrp_state_master_tx(...) = 1 * register a gratuitous arp thread delayed to 5 secs. */ if (vrrp_state_master_tx(vrrp, 0)) { thread_add_timer(master, vrrp_gratuitous_arp_thread, vrrp, (vrrp->garp_delay) ? vrrp->garp_delay : VRRP_GARP_DELAY); vrrp_smtp_notifier(vrrp); } } } static void vrrp_fault(vrrp_t * vrrp) { vrrp_sgroup_t *vgroup = vrrp->sync; if (vgroup) { if (!vrrp_sync_leave_fault(vrrp)) return; } else if (VRRP_ISUP(vrrp)) vrrp_log_int_up(vrrp); else return; /* refresh the multicast fd */ if (new_vrrp_socket(vrrp) < 0) return; /* * We force the IPSEC AH seq_number sync * to be done in read advert handler. * So we ignore this timeouted state until remote * VRRP MASTER send its advert for the concerned * instance. */ if (vrrp->auth_type == VRRP_AUTH_AH) { vrrp_ah_sync(vrrp); } else { /* Otherwise, we transit to init state */ if (vrrp->init_state == VRRP_STATE_BACK) { vrrp->state = VRRP_STATE_BACK; notify_instance_exec(vrrp, VRRP_STATE_BACK); #ifdef _WITH_SNMP_ vrrp_snmp_instance_trap(vrrp); #endif } else { vrrp_goto_master(vrrp); } } } /* Handle dispatcher read timeout */ static int vrrp_dispatcher_read_to(int fd) { vrrp_t *vrrp; int vrid = 0; int prev_state = 0; /* Searching for matching instance */ vrid = vrrp_timer_vrid_timeout(fd); vrrp = vrrp_index_lookup(vrid, fd); /* Run the FSM handler */ prev_state = vrrp->state; VRRP_FSM_READ_TO(vrrp); /* handle instance synchronization */ // printf("Send [%s] TSM transtition : [%d,%d] Wantstate = [%d]\n" // , vrrp->iname // , prev_state // , vrrp->state // , vrrp->wantstate); VRRP_TSM_HANDLE(prev_state, vrrp); /* * We are sure the instance exist. So we can * compute new sands timer safely. */ vrrp_init_instance_sands(vrrp); /* * If quick sync is set, refresh sands to one advert interval, i.e. the next * timeout will occur in one interval instead of three, and a check for a * possible transition check will perform more quickly. */ if (vrrp->quick_sync) { vrrp->sands = timer_add_long(time_now, vrrp->adver_int); vrrp->quick_sync = 0; } return vrrp->fd_in; } /* Handle dispatcher read packet */ static int vrrp_dispatcher_read(sock_t * sock) { vrrp_t *vrrp; vrrphdr_t *hd; int len = 0, prev_state = 0, proto = 0; uint32_t saddr; /* Clean the read buffer */ memset(vrrp_buffer, 0, VRRP_PACKET_TEMP_LEN); /* read & affect received buffer */ len = read(sock->fd_in, vrrp_buffer, VRRP_PACKET_TEMP_LEN); hd = vrrp_get_header(sock->family, vrrp_buffer, &proto, &saddr); /* Searching for matching instance */ vrrp = vrrp_index_lookup(hd->vrid, sock->fd_in); /* If no instance found => ignore the advert */ if (!vrrp) return sock->fd_in; /* Run the FSM handler */ prev_state = vrrp->state; VRRP_FSM_READ(vrrp, vrrp_buffer, len); /* handle instance synchronization */ // printf("Read [%s] TSM transtition : [%d,%d] Wantstate = [%d]\n" // , vrrp->iname // , prev_state // , vrrp->state // , vrrp->wantstate); VRRP_TSM_HANDLE(prev_state, vrrp); /* * Refresh sands only if found matching instance. * Otherwize the packet is simply ignored... */ vrrp_init_instance_sands(vrrp); return sock->fd_in; } /* Our read packet dispatcher */ int vrrp_read_dispatcher_thread(thread_t * thread) { long vrrp_timer = 0; sock_t *sock; int fd; /* Fetch thread arg */ sock = THREAD_ARG(thread); /* Dispatcher state handler */ if (thread->type == THREAD_READ_TIMEOUT || sock->fd_in == -1) fd = vrrp_dispatcher_read_to(sock->fd_in); else fd = vrrp_dispatcher_read(sock); /* register next dispatcher thread */ vrrp_timer = vrrp_timer_fd(fd); if (fd == -1) sock->thread = thread_add_timer(thread->master, vrrp_read_dispatcher_thread, sock, vrrp_timer); else sock->thread = thread_add_read(thread->master, vrrp_read_dispatcher_thread, sock, fd, vrrp_timer); return 0; } /* Script tracking threads */ static int vrrp_script_thread(thread_t * thread) { vrrp_script_t *vscript = THREAD_ARG(thread); int status, ret; pid_t pid; /* Register next timer tracker */ thread_add_timer(thread->master, vrrp_script_thread, vscript, vscript->interval); /* Daemonization to not degrade our scheduling timer */ pid = fork(); /* In case of fork is error. */ if (pid < 0) { log_message(LOG_INFO, "Failed fork process"); return -1; } /* In case of this is parent process */ if (pid) { thread_add_child(thread->master, vrrp_script_child_thread, vscript, pid, (vscript->timeout) ? vscript->timeout : vscript->interval); return 0; } /* Child part */ signal_handler_destroy(); closeall(0); open("/dev/null", O_RDWR); ret = dup(0); if (ret < 0) { log_message(LOG_INFO, "dup(0) error"); } ret = dup(0); if (ret < 0) { log_message(LOG_INFO, "dup(0) error"); } status = system_call(vscript->script); if (status < 0 || !WIFEXITED(status)) status = 0; /* Script errors aren't server errors */ else status = WEXITSTATUS(status); exit(status); } static int vrrp_script_child_thread(thread_t * thread) { int wait_status; vrrp_script_t *vscript = THREAD_ARG(thread); if (thread->type == THREAD_CHILD_TIMEOUT) { pid_t pid; pid = THREAD_CHILD_PID(thread); /* The child hasn't responded. Kill it off. */ if (vscript->result > vscript->rise) { vscript->result--; } else { if (vscript->result == vscript->rise) log_message(LOG_INFO, "VRRP_Script(%s) timed out", vscript->sname); vscript->result = 0; } kill(pid, SIGTERM); thread_add_child(thread->master, vrrp_script_child_timeout_thread, vscript, pid, 2); return 0; } wait_status = THREAD_CHILD_STATUS(thread); if (WIFEXITED(wait_status)) { int status; status = WEXITSTATUS(wait_status); if (status == 0) { /* success */ if (vscript->result < vscript->rise - 1) { vscript->result++; } else { if (vscript->result < vscript->rise) log_message(LOG_INFO, "VRRP_Script(%s) succeeded", vscript->sname); vscript->result = vscript->rise + vscript->fall - 1; } } else { /* failure */ if (vscript->result > vscript->rise) { vscript->result--; } else { if (vscript->result >= vscript->rise) log_message(LOG_INFO, "VRRP_Script(%s) failed", vscript->sname); vscript->result = 0; } } } return 0; } static int vrrp_script_child_timeout_thread(thread_t * thread) { pid_t pid; if (thread->type != THREAD_CHILD_TIMEOUT) return 0; /* OK, it still hasn't exited. Now really kill it off. */ pid = THREAD_CHILD_PID(thread); if (kill(pid, SIGKILL) < 0) { /* Its possible it finished while we're handing this */ if (errno != ESRCH) DBG("kill error: %s", strerror(errno)); return 0; } log_message(LOG_WARNING, "Process [%d] didn't respond to SIGTERM", pid); waitpid(pid, NULL, 0); return 0; } keepalived-1.2.13/keepalived/core/0000775000175000017500000000000012334417517016575 5ustar acassenacassenkeepalived-1.2.13/keepalived/core/pidfile.c0000664000175000017500000000501312211121152020331 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: pidfile utility. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include #include #include #include "logger.h" #include "pidfile.h" extern char *main_pidfile; extern char *checkers_pidfile; extern char *vrrp_pidfile; /* Create the runnnig daemon pidfile */ int pidfile_write(char *pid_file, int pid) { FILE *pidfile = NULL; int pidfd = creat(pid_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (pidfd != -1) pidfile = fdopen(pidfd, "w"); if (!pidfile) { log_message(LOG_INFO, "pidfile_write : Can not open %s pidfile", pid_file); return 0; } fprintf(pidfile, "%d\n", pid); fclose(pidfile); return 1; } /* Remove the running daemon pidfile */ void pidfile_rm(char *pid_file) { unlink(pid_file); } /* return the daemon running state */ int process_running(char *pid_file) { FILE *pidfile = fopen(pid_file, "r"); pid_t pid; int ret; /* No pidfile */ if (!pidfile) return 0; ret = fscanf(pidfile, "%d", &pid); if (ret == EOF && ferror(pidfile) != 0) { log_message(LOG_INFO, "Error opening pid file %s", pid_file); } fclose(pidfile); /* If no process is attached to pidfile, remove it */ if (kill(pid, 0)) { log_message(LOG_INFO, "Remove a zombie pid file %s", pid_file); pidfile_rm(pid_file); return 0; } return 1; } /* Return parent process daemon state */ int keepalived_running(int mode) { if (process_running(main_pidfile)) return 1; else if (mode & 1 || mode & 2) return process_running((mode & 1) ? vrrp_pidfile : checkers_pidfile); if (process_running(vrrp_pidfile) || process_running(checkers_pidfile)) return 1; return 0; } keepalived-1.2.13/keepalived/core/smtp.c0000664000175000017500000003725312211121152017713 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: SMTP WRAPPER connect to a specified smtp server and send mail * using the smtp protocol according to the RFC 821. A non blocking * timeouted connection is used to handle smtp protocol. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include #include "smtp.h" #include "global_data.h" #include "check_data.h" #include "scheduler.h" #include "memory.h" #include "list.h" #include "logger.h" #include "utils.h" /* SMTP FSM definition */ static int connection_error(thread_t *); static int connection_in_progress(thread_t *); static int connection_timeout(thread_t *); static int connection_success(thread_t *); static int helo_cmd(thread_t *); static int mail_cmd(thread_t *); static int rcpt_cmd(thread_t *); static int data_cmd(thread_t *); static int body_cmd(thread_t *); static int quit_cmd(thread_t *); static int connection_code(thread_t *, int); static int helo_code(thread_t *, int); static int mail_code(thread_t *, int); static int rcpt_code(thread_t *, int); static int data_code(thread_t *, int); static int body_code(thread_t *, int); static int quit_code(thread_t *, int); static int smtp_read_thread(thread_t *); static int smtp_send_thread(thread_t *); struct { int (*send) (thread_t *); int (*read) (thread_t *, int); } SMTP_FSM[SMTP_MAX_FSM_STATE] = { /* Stream Write Handlers | Stream Read handlers * *-------------------------------+--------------------------*/ {connection_error, NULL}, /* connect_error */ {connection_in_progress, NULL}, /* connect_in_progress */ {connection_timeout, NULL}, /* connect_timeout */ {connection_success, connection_code}, /* connect_success */ {helo_cmd, helo_code}, /* HELO */ {mail_cmd, mail_code}, /* MAIL */ {rcpt_cmd, rcpt_code}, /* RCPT */ {data_cmd, data_code}, /* DATA */ {body_cmd, body_code}, /* BODY */ {quit_cmd, quit_code} /* QUIT */ }; static void free_smtp_all(smtp_t * smtp) { FREE(smtp->buffer); FREE(smtp->subject); FREE(smtp->body); FREE(smtp->email_to); FREE(smtp); } static char * fetch_next_email(smtp_t * smtp) { return list_element(global_data->email, smtp->email_it); } /* layer4 connection handlers */ static int connection_error(thread_t * thread) { smtp_t *smtp = THREAD_ARG(thread); log_message(LOG_INFO, "SMTP connection ERROR to [%s]:%d." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); free_smtp_all(smtp); return 0; } static int connection_timeout(thread_t * thread) { smtp_t *smtp = THREAD_ARG(thread); log_message(LOG_INFO, "Timeout connecting SMTP server [%s]:%d." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); free_smtp_all(smtp); return 0; } static int connection_in_progress(thread_t * thread) { int status; DBG("SMTP connection to [%s]:%d now IN_PROGRESS.", inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); /* * Here we use the propriety of a union structure, * each element of the structure have the same value. */ status = tcp_socket_state(thread->u.fd, thread, connection_in_progress); if (status != connect_in_progress) SMTP_FSM_SEND(status, thread); return 0; } static int connection_success(thread_t * thread) { smtp_t *smtp = THREAD_ARG(thread); log_message(LOG_INFO, "Remote SMTP server [%s]:%d connected." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); smtp->stage = connect_success; thread_add_read(thread->master, smtp_read_thread, smtp, smtp->fd, global_data->smtp_connection_to); return 0; } /* SMTP protocol handlers */ static int smtp_read_thread(thread_t * thread) { smtp_t *smtp; char *buffer; char *reply; int rcv_buffer_size = 0; int status = -1; smtp = THREAD_ARG(thread); if (thread->type == THREAD_READ_TIMEOUT) { log_message(LOG_INFO, "Timeout reading data to remote SMTP server [%s]:%d." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); SMTP_FSM_READ(QUIT, thread, 0); return -1; } buffer = smtp->buffer; rcv_buffer_size = read(thread->u.fd, buffer + smtp->buflen, SMTP_BUFFER_LENGTH - smtp->buflen); if (rcv_buffer_size == -1) { if (errno == EAGAIN) goto end; log_message(LOG_INFO, "Error reading data from remote SMTP server [%s]:%d." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); SMTP_FSM_READ(QUIT, thread, 0); return 0; } /* received data overflow buffer size ? */ if (smtp->buflen >= SMTP_BUFFER_MAX) { log_message(LOG_INFO, "Received buffer from remote SMTP server [%s]:%d" " overflow our get read buffer length." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); SMTP_FSM_READ(QUIT, thread, 0); return 0; } else { smtp->buflen += rcv_buffer_size; buffer[smtp->buflen] = 0; /* NULL terminate */ } end: /* parse the buffer, finding the last line of the response for the code */ reply = buffer; while (reply < buffer + smtp->buflen) { char *p; p = strstr(reply, "\r\n"); if (!p) { memmove(buffer, reply, smtp->buflen - (reply - buffer)); smtp->buflen -= (reply - buffer); buffer[smtp->buflen] = 0; thread_add_read(thread->master, smtp_read_thread, smtp, thread->u.fd, global_data->smtp_connection_to); return 0; } if (reply[3] == '-') { /* Skip over the \r\n */ reply = p + 2; continue; } status = ((reply[0] - '0') * 100) + ((reply[1] - '0') * 10) + (reply[2] - '0'); reply = p + 2; break; } memmove(buffer, reply, smtp->buflen - (reply - buffer)); smtp->buflen -= (reply - buffer); buffer[smtp->buflen] = 0; if (status == -1) { thread_add_read(thread->master, smtp_read_thread, smtp, thread->u.fd, global_data->smtp_connection_to); return 0; } SMTP_FSM_READ(smtp->stage, thread, status); /* Registering next smtp command processing thread */ if (smtp->stage != ERROR) { thread_add_write(thread->master, smtp_send_thread, smtp, smtp->fd, global_data->smtp_connection_to); } else { log_message(LOG_INFO, "Can not read data from remote SMTP server [%s]:%d." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); SMTP_FSM_READ(QUIT, thread, 0); } return 0; } static int smtp_send_thread(thread_t * thread) { smtp_t *smtp = THREAD_ARG(thread); if (thread->type == THREAD_WRITE_TIMEOUT) { log_message(LOG_INFO, "Timeout sending data to remote SMTP server [%s]:%d." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); SMTP_FSM_READ(QUIT, thread, 0); return 0; } SMTP_FSM_SEND(smtp->stage, thread); /* Handle END command */ if (smtp->stage == END) { SMTP_FSM_READ(QUIT, thread, 0); return 0; } /* Registering next smtp command processing thread */ if (smtp->stage != ERROR) { thread_add_read(thread->master, smtp_read_thread, smtp, thread->u.fd, global_data->smtp_connection_to); } else { log_message(LOG_INFO, "Can not send data to remote SMTP server [%s]:%d." , inet_sockaddrtos(&global_data->smtp_server) , SMTP_PORT); SMTP_FSM_READ(QUIT, thread, 0); } return 0; } static int connection_code(thread_t * thread, int status) { smtp_t *smtp = THREAD_ARG(thread); if (status == 220) { smtp->stage++; } else { log_message(LOG_INFO, "Error connecting SMTP server[%s]:%d." " SMTP status code = %d" , inet_sockaddrtos(&global_data->smtp_server) , SMTP_PORT, status); smtp->stage = ERROR; } return 0; } /* HELO command processing */ static int helo_cmd(thread_t * thread) { smtp_t *smtp = THREAD_ARG(thread); char *buffer; buffer = (char *) MALLOC(SMTP_BUFFER_MAX); snprintf(buffer, SMTP_BUFFER_MAX, SMTP_HELO_CMD, get_local_name()); if (send(thread->u.fd, buffer, strlen(buffer), 0) == -1) smtp->stage = ERROR; FREE(buffer); return 0; } static int helo_code(thread_t * thread, int status) { smtp_t *smtp = THREAD_ARG(thread); if (status == 250) { smtp->stage++; } else { log_message(LOG_INFO, "Error processing HELO cmd on SMTP server [%s]:%d." " SMTP status code = %d" , inet_sockaddrtos(&global_data->smtp_server) , SMTP_PORT, status); smtp->stage = ERROR; } return 0; } /* MAIL command processing */ static int mail_cmd(thread_t * thread) { smtp_t *smtp = THREAD_ARG(thread); char *buffer; buffer = (char *) MALLOC(SMTP_BUFFER_MAX); snprintf(buffer, SMTP_BUFFER_MAX, SMTP_MAIL_CMD, global_data->email_from); if (send(thread->u.fd, buffer, strlen(buffer), 0) == -1) smtp->stage = ERROR; FREE(buffer); return 0; } static int mail_code(thread_t * thread, int status) { smtp_t *smtp = THREAD_ARG(thread); if (status == 250) { smtp->stage++; } else { log_message(LOG_INFO, "Error processing MAIL cmd on SMTP server [%s]:%d." " SMTP status code = %d" , inet_sockaddrtos(&global_data->smtp_server) , SMTP_PORT, status); smtp->stage = ERROR; } return 0; } /* RCPT command processing */ static int rcpt_cmd(thread_t * thread) { smtp_t *smtp = THREAD_ARG(thread); char *buffer; char *fetched_email; buffer = (char *) MALLOC(SMTP_BUFFER_MAX); /* We send RCPT TO command multiple time to add all our email receivers. * --rfc821.3.1 */ fetched_email = fetch_next_email(smtp); snprintf(buffer, SMTP_BUFFER_MAX, SMTP_RCPT_CMD, fetched_email); if (send(thread->u.fd, buffer, strlen(buffer), 0) == -1) smtp->stage = ERROR; FREE(buffer); return 0; } static int rcpt_code(thread_t * thread, int status) { smtp_t *smtp = THREAD_ARG(thread); char *fetched_email; if (status == 250) { smtp->email_it++; fetched_email = fetch_next_email(smtp); if (!fetched_email) smtp->stage++; } else { log_message(LOG_INFO, "Error processing RCPT cmd on SMTP server [%s]:%d." " SMTP status code = %d" , inet_sockaddrtos(&global_data->smtp_server) , SMTP_PORT, status); smtp->stage = ERROR; } return 0; } /* DATA command processing */ static int data_cmd(thread_t * thread) { smtp_t *smtp = THREAD_ARG(thread); if (send(thread->u.fd, SMTP_DATA_CMD, strlen(SMTP_DATA_CMD), 0) == -1) smtp->stage = ERROR; return 0; } static int data_code(thread_t * thread, int status) { smtp_t *smtp = THREAD_ARG(thread); if (status == 354) { smtp->stage++; } else { log_message(LOG_INFO, "Error processing DATA cmd on SMTP server [%s]:%d." " SMTP status code = %d" , inet_sockaddrtos(&global_data->smtp_server) , SMTP_PORT, status); smtp->stage = ERROR; } return 0; } /* * Build a comma separated string of smtp recipient email addresses * for the email message To-header. */ void build_to_header_rcpt_addrs(smtp_t *smtp) { char *fetched_email; char *email_to_addrs; int email_addrs_max; if (smtp == NULL) return; email_to_addrs = smtp->email_to; smtp->email_it = 0; email_addrs_max = (SMTP_BUFFER_MAX / SMTP_EMAIL_ADDR_MAX_LENGTH) - 1; while ((fetched_email = fetch_next_email(smtp)) != NULL) { /* First email address, so no need for "," */ if (smtp->email_it == 0) { snprintf(email_to_addrs, SMTP_EMAIL_ADDR_MAX_LENGTH, "%s", fetched_email); } else { strcat(email_to_addrs, ", "); strncat(email_to_addrs, fetched_email, SMTP_EMAIL_ADDR_MAX_LENGTH); } smtp->email_it++; if (smtp->email_it >= email_addrs_max) break; } smtp->email_it = 0; } /* BODY command processing. * Do we need to use mutli-thread for multi-part body * handling ? Don t really think :) */ static int body_cmd(thread_t * thread) { smtp_t *smtp = THREAD_ARG(thread); char *buffer; char rfc822[80]; time_t tm; buffer = (char *) MALLOC(SMTP_BUFFER_MAX); time(&tm); strftime(rfc822, sizeof(rfc822), "%a, %d %b %Y %H:%M:%S %z", gmtime(&tm)); snprintf(buffer, SMTP_BUFFER_MAX, SMTP_HEADERS_CMD, rfc822, global_data->email_from, smtp->subject, smtp->email_to); /* send the subject field */ if (send(thread->u.fd, buffer, strlen(buffer), 0) == -1) smtp->stage = ERROR; memset(buffer, 0, SMTP_BUFFER_MAX); snprintf(buffer, SMTP_BUFFER_MAX, SMTP_BODY_CMD, smtp->body); /* send the the body field */ if (send(thread->u.fd, buffer, strlen(buffer), 0) == -1) smtp->stage = ERROR; /* send the sending dot */ if (send(thread->u.fd, SMTP_SEND_CMD, strlen(SMTP_SEND_CMD), 0) == -1) smtp->stage = ERROR; FREE(buffer); return 0; } static int body_code(thread_t * thread, int status) { smtp_t *smtp = THREAD_ARG(thread); if (status == 250) { log_message(LOG_INFO, "SMTP alert successfully sent."); smtp->stage++; } else { log_message(LOG_INFO, "Error processing DOT cmd on SMTP server [%s]:%d." " SMTP status code = %d" , inet_sockaddrtos(&global_data->smtp_server) , SMTP_PORT, status); smtp->stage = ERROR; } return 0; } /* QUIT command processing */ static int quit_cmd(thread_t * thread) { smtp_t *smtp = THREAD_ARG(thread); if (send(thread->u.fd, SMTP_QUIT_CMD, strlen(SMTP_QUIT_CMD), 0) == -1) smtp->stage = ERROR; else smtp->stage++; return 0; } static int quit_code(thread_t * thread, int status) { smtp_t *smtp = THREAD_ARG(thread); /* final state, we are disconnected from the remote host */ free_smtp_all(smtp); close(thread->u.fd); return 0; } /* connect remote SMTP server */ static void smtp_connect(smtp_t * smtp) { enum connect_result status; if ((smtp->fd = socket(global_data->smtp_server.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { DBG("SMTP connect fail to create socket."); free_smtp_all(smtp); return; } status = tcp_connect(smtp->fd, &global_data->smtp_server); /* Handle connection status code */ thread_add_event(master, SMTP_FSM[status].send, smtp, smtp->fd); } /* Main entry point */ void smtp_alert(real_server_t * rs, vrrp_t * vrrp, vrrp_sgroup_t * vgroup, const char *subject, const char *body) { smtp_t *smtp; /* Only send mail if email specified */ if (!LIST_ISEMPTY(global_data->email) && global_data->smtp_server.ss_family != 0) { /* allocate & initialize smtp argument data structure */ smtp = (smtp_t *) MALLOC(sizeof(smtp_t)); smtp->subject = (char *) MALLOC(MAX_HEADERS_LENGTH); smtp->body = (char *) MALLOC(MAX_BODY_LENGTH); smtp->buffer = (char *) MALLOC(SMTP_BUFFER_MAX); smtp->email_to = (char *) MALLOC(SMTP_BUFFER_MAX); /* format subject if rserver is specified */ if (rs) { snprintf(smtp->subject, MAX_HEADERS_LENGTH, "[%s] Realserver [%s]:%d - %s" , global_data->router_id , inet_sockaddrtos(&rs->addr) , ntohs(inet_sockaddrport(&rs->addr)) , subject); } else if (vrrp) snprintf(smtp->subject, MAX_HEADERS_LENGTH, "[%s] VRRP Instance %s - %s" , global_data->router_id , vrrp->iname , subject); else if (vgroup) snprintf(smtp->subject, MAX_HEADERS_LENGTH, "[%s] VRRP Group %s - %s" , global_data->router_id , vgroup->gname , subject); else if (global_data->router_id) snprintf(smtp->subject, MAX_HEADERS_LENGTH, "[%s] %s" , global_data->router_id , subject); else snprintf(smtp->subject, MAX_HEADERS_LENGTH, "%s", subject); strncpy(smtp->body, body, MAX_BODY_LENGTH); build_to_header_rcpt_addrs(smtp); smtp_connect(smtp); } } keepalived-1.2.13/keepalived/core/global_data.c0000664000175000017500000001071212261336065021170 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Dynamic data structure definition. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include #include #include #include #include "global_data.h" #include "memory.h" #include "list.h" #include "logger.h" #include "utils.h" /* global vars */ data_t *global_data = NULL; /* Default settings */ static void set_default_router_id(data_t * data) { char *new_id = NULL; int len = 0; new_id = get_local_name(); if (!new_id || !new_id[0]) return; len = strlen(new_id); data->router_id = MALLOC(len + 1); if (!data->router_id) return; memcpy(data->router_id, new_id, len); } static void set_default_email_from(data_t * data) { struct passwd *pwd = NULL; char *hostname = NULL; int len = 0; hostname = get_local_name(); if (!hostname || !hostname[0]) return; pwd = getpwuid(getuid()); if (!pwd) return; len = strlen(hostname) + strlen(pwd->pw_name) + 2; data->email_from = MALLOC(len); if (!data->email_from) return; snprintf(data->email_from, len, "%s@%s", pwd->pw_name, hostname); } static void set_default_smtp_connection_timeout(data_t * data) { data->smtp_connection_to = DEFAULT_SMTP_CONNECTION_TIMEOUT; } static void set_default_mcast_group(data_t * data) { inet_stosockaddr("224.0.0.18", 0, &data->vrrp_mcast_group4); inet_stosockaddr("ff02::12", 0, &data->vrrp_mcast_group6); } static void set_default_values(data_t * data) { /* No global data so don't default */ if (!data) return; set_default_router_id(data); set_default_smtp_connection_timeout(data); set_default_email_from(data); set_default_mcast_group(data); } /* email facility functions */ static void free_email(void *data) { FREE(data); } static void dump_email(void *data) { char *addr = data; log_message(LOG_INFO, " Email notification = %s", addr); } void alloc_email(char *addr) { int size = strlen(addr); char *new; new = (char *) MALLOC(size + 1); memcpy(new, addr, size + 1); list_add(global_data->email, new); } /* data facility functions */ data_t * alloc_global_data(void) { data_t *new; new = (data_t *) MALLOC(sizeof(data_t)); new->email = alloc_list(free_email, dump_email); set_default_values(new); return new; } void free_global_data(data_t * data) { free_list(data->email); FREE_PTR(data->router_id); FREE_PTR(data->plugin_dir); FREE_PTR(data->email_from); FREE(data); } void dump_global_data(data_t * data) { if (!data) return; if (data->router_id || data->smtp_server.ss_family || data->smtp_connection_to || data->email_from) { log_message(LOG_INFO, "------< Global definitions >------"); } if (data->router_id) log_message(LOG_INFO, " Router ID = %s", data->router_id); if (data->plugin_dir) log_message(LOG_INFO, " Plugin dir = %s", data->plugin_dir); if (data->smtp_server.ss_family) log_message(LOG_INFO, " Smtp server = %s", inet_sockaddrtos(&data->smtp_server)); if (data->smtp_connection_to) log_message(LOG_INFO, " Smtp server connection timeout = %lu" , data->smtp_connection_to / TIMER_HZ); if (data->email_from) { log_message(LOG_INFO, " Email notification from = %s" , data->email_from); dump_list(data->email); } if (data->vrrp_mcast_group4.ss_family) { log_message(LOG_INFO, " VRRP IPv4 mcast group = %s" , inet_sockaddrtos(&data->vrrp_mcast_group4)); } if (data->vrrp_mcast_group6.ss_family) { log_message(LOG_INFO, " VRRP IPv6 mcast group = %s" , inet_sockaddrtos(&data->vrrp_mcast_group4)); } #ifdef _WITH_SNMP_ if (data->enable_traps) log_message(LOG_INFO, " SNMP Trap enabled"); else log_message(LOG_INFO, " SNMP Trap disabled"); #endif } keepalived-1.2.13/keepalived/core/Makefile.in0000644000175000017500000000260312334072037020633 0ustar acassenacassen# Makefile # # Keepalived OpenSource project. # # Copyright (C) 2001-2012 Alexandre Cassen, CC = @CC@ SNMP_FLAG = @SNMP_SUPPORT@ INCLUDES = -I../include -I../../lib CFLAGS = @CFLAGS@ @CPPFLAGS@ $(INCLUDES) \ -Wall -Wunused -Wstrict-prototypes DEFS = -D@KERN@ -D@IPVS_SUPPORT@ -D@VRRP_SUPPORT@ -D@SNMP_SUPPORT@ -D@SO_MARK_SUPPORT@ @DFLAGS@ COMPILE = $(CC) $(CFLAGS) $(DEFS) OBJS = main.o daemon.o pidfile.o layer4.o smtp.o \ global_data.o global_parser.o ifeq ($(SNMP_FLAG),_WITH_SNMP_) OBJS += snmp.o endif HEADERS = $(OBJS:.o=.h) .c.o: $(COMPILE) -c $< all: $(OBJS) clean: rm -f *.a *.o *~ distclean: clean rm -f Makefile main.o: main.c ../include/main.h ../../lib/config.h ../../lib/signals.h daemon.o: daemon.c ../include/daemon.h ../../lib/utils.h pidfile.o: pidfile.c ../include/pidfile.h layer4.o: layer4.c ../include/layer4.h ../include/check_api.h ../../lib/utils.h smtp.o: smtp.c ../include/smtp.h ../include/global_data.h ../../lib/memory.h \ ../../lib/list.h ../../lib/utils.h global_data.o: global_data.c ../include/global_data.h ../../lib/memory.h \ ../../lib/list.h ../../lib/utils.h global_parser.o: global_parser.c ../include/global_parser.h \ ../include/global_data.h ../../lib/parser.h ../../lib/memory.h \ ../../lib/utils.h snmp.o: snmp.c ../include/snmp.h ../../lib/logger.h ../../lib/list.h \ ../../lib/config.h ../include/global_data.h keepalived-1.2.13/keepalived/core/main.c0000644000175000017500000002050412260316507017657 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Main program structure. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "main.h" #include "config.h" #include "signals.h" #include "pidfile.h" #include "logger.h" /* global var */ char *conf_file = NULL; /* Configuration file */ int log_facility = LOG_DAEMON; /* Optional logging facilities */ pid_t vrrp_child = -1; /* VRRP child process ID */ pid_t checkers_child = -1; /* Healthcheckers child process ID */ int daemon_mode = 0; /* VRRP/CHECK subsystem selection */ int linkwatch = 0; /* Use linkwatch kernel netlink reflection */ char *main_pidfile = KEEPALIVED_PID_FILE; /* overrule default pidfile */ char *checkers_pidfile = CHECKERS_PID_FILE; /* overrule default pidfile */ char *vrrp_pidfile = VRRP_PID_FILE; /* overrule default pidfile */ #ifdef _WITH_SNMP_ int snmp = 0; /* Enable SNMP support */ #endif /* Log facility table */ static struct { int facility; } LOG_FACILITY[LOG_FACILITY_MAX + 1] = { {LOG_LOCAL0}, {LOG_LOCAL1}, {LOG_LOCAL2}, {LOG_LOCAL3}, {LOG_LOCAL4}, {LOG_LOCAL5}, {LOG_LOCAL6}, {LOG_LOCAL7} }; /* Daemon stop sequence */ static void stop_keepalived(void) { log_message(LOG_INFO, "Stopping " VERSION_STRING); /* Just cleanup memory & exit */ signal_handler_destroy(); thread_destroy_master(master); pidfile_rm(main_pidfile); if (daemon_mode & 1 || !daemon_mode) pidfile_rm(vrrp_pidfile); if (daemon_mode & 2 || !daemon_mode) pidfile_rm(checkers_pidfile); #ifdef _DEBUG_ keepalived_free_final("Parent process"); #endif } /* Daemon init sequence */ static void start_keepalived(void) { #ifdef _WITH_LVS_ /* start healthchecker child */ if (daemon_mode & 2 || !daemon_mode) start_check_child(); #endif #ifdef _WITH_VRRP_ /* start vrrp child */ if (daemon_mode & 1 || !daemon_mode) start_vrrp_child(); #endif } /* SIGHUP handler */ void sighup(void *v, int sig) { /* Signal child process */ if (vrrp_child > 0) kill(vrrp_child, SIGHUP); if (checkers_child > 0) kill(checkers_child, SIGHUP); } /* Terminate handler */ void sigend(void *v, int sig) { int status; /* register the terminate thread */ thread_add_terminate_event(master); if (vrrp_child > 0) { kill(vrrp_child, SIGTERM); waitpid(vrrp_child, &status, WNOHANG); } if (checkers_child > 0) { kill(checkers_child, SIGTERM); waitpid(checkers_child, &status, WNOHANG); } } /* Initialize signal handler */ void signal_init(void) { signal_handler_init(); signal_set(SIGHUP, sighup, NULL); signal_set(SIGINT, sigend, NULL); signal_set(SIGTERM, sigend, NULL); signal_ignore(SIGPIPE); } /* Usage function */ static void usage(const char *prog) { fprintf(stderr, "Usage: %s [OPTION...]\n", prog); fprintf(stderr, " -f, --use-file=FILE Use the specified configuration file\n"); fprintf(stderr, " -P, --vrrp Only run with VRRP subsystem\n"); fprintf(stderr, " -C, --check Only run with Health-checker subsystem\n"); fprintf(stderr, " -l, --log-console Log messages to local console\n"); fprintf(stderr, " -D, --log-detail Detailed log messages\n"); fprintf(stderr, " -S, --log-facility=[0-7] Set syslog facility to LOG_LOCAL[0-7]\n"); fprintf(stderr, " -V, --dont-release-vrrp Don't remove VRRP VIPs and VROUTEs on daemon stop\n"); fprintf(stderr, " -I, --dont-release-ipvs Don't remove IPVS topology on daemon stop\n"); fprintf(stderr, " -R, --dont-respawn Don't respawn child processes\n"); fprintf(stderr, " -n, --dont-fork Don't fork the daemon process\n"); fprintf(stderr, " -d, --dump-conf Dump the configuration data\n"); fprintf(stderr, " -p, --pid=FILE Use specified pidfile for parent process\n"); fprintf(stderr, " -r, --vrrp_pid=FILE Use specified pidfile for VRRP child process\n"); fprintf(stderr, " -c, --checkers_pid=FILE Use specified pidfile for checkers child process\n"); #ifdef _WITH_SNMP_ fprintf(stderr, " -x, --snmp Enable SNMP subsystem\n"); #endif fprintf(stderr, " -v, --version Display the version number\n"); fprintf(stderr, " -h, --help Display this help message\n"); } /* Command line parser */ static void parse_cmdline(int argc, char **argv) { int c; struct option long_options[] = { {"use-file", required_argument, 0, 'f'}, {"vrrp", no_argument, 0, 'P'}, {"check", no_argument, 0, 'C'}, {"log-console", no_argument, 0, 'l'}, {"log-detail", no_argument, 0, 'D'}, {"log-facility", required_argument, 0, 'S'}, {"dont-release-vrrp", no_argument, 0, 'V'}, {"dont-release-ipvs", no_argument, 0, 'I'}, {"dont-respawn", no_argument, 0, 'R'}, {"dont-fork", no_argument, 0, 'n'}, {"dump-conf", no_argument, 0, 'd'}, {"pid", required_argument, 0, 'p'}, {"vrrp_pid", required_argument, 0, 'r'}, {"checkers_pid", required_argument, 0, 'c'}, #ifdef _WITH_SNMP_ {"snmp", no_argument, 0, 'x'}, #endif {"version", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; #ifdef _WITH_SNMP_ while ((c = getopt_long(argc, argv, "vhlndVIDRS:f:PCp:c:r:x", long_options, NULL)) != EOF) { #else while ((c = getopt_long(argc, argv, "vhlndVIDRS:f:PCp:c:r:", long_options, NULL)) != EOF) { #endif switch (c) { case 'v': fprintf(stderr, VERSION_STRING); exit(0); break; case 'h': usage(argv[0]); exit(0); break; case 'l': debug |= 1; break; case 'n': debug |= 2; break; case 'd': debug |= 4; break; case 'V': debug |= 8; break; case 'I': debug |= 16; break; case 'D': debug |= 32; break; case 'R': debug |= 64; break; case 'S': log_facility = LOG_FACILITY[atoi(optarg)].facility; break; case 'f': conf_file = optarg; break; case 'P': daemon_mode |= 1; break; case 'C': daemon_mode |= 2; break; case 'p': main_pidfile = optarg; break; case 'c': checkers_pidfile = optarg; break; case 'r': vrrp_pidfile = optarg; break; #ifdef _WITH_SNMP_ case 'x': snmp = 1; break; #endif default: exit(0); break; } } if (optind < argc) { printf("Unexpected argument(s): "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } } /* Entry point */ int main(int argc, char **argv) { /* Init debugging level */ mem_allocated = 0; debug = 0; /* * Parse command line and set debug level. * bits 0..7 reserved by main.c */ parse_cmdline(argc, argv); openlog(PROG, LOG_PID | ((debug & 1) ? LOG_CONS : 0), log_facility); log_message(LOG_INFO, "Starting " VERSION_STRING); /* Check if keepalived is already running */ if (keepalived_running(daemon_mode)) { log_message(LOG_INFO, "daemon is already running"); goto end; } if (debug & 1) enable_console_log(); /* daemonize process */ if (!(debug & 2)) xdaemon(0, 0, 0); /* write the father's pidfile */ if (!pidfile_write(main_pidfile, getpid())) goto end; #ifndef _DEBUG_ /* Signal handling initialization */ signal_init(); #endif /* Create the master thread */ master = thread_make_master(); /* Init daemon */ start_keepalived(); #ifndef _DEBUG_ /* Launch the scheduling I/O multiplexer */ launch_scheduler(); /* Finish daemon process */ stop_keepalived(); #endif /* * Reached when terminate signal catched. * finally return from system */ end: closelog(); exit(0); } keepalived-1.2.13/keepalived/core/snmp.c0000664000175000017500000001651112211121152017677 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: SNMP framework * * Authors: Vincent Bernat * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "snmp.h" #include "logger.h" #include "config.h" #include "global_data.h" static int snmp_keepalived_log(int major, int minor, void *serverarg, void *clientarg) { struct snmp_log_message *slm = (struct snmp_log_message*)serverarg; log_message(slm->priority, "%s", slm->msg); return 0; } /* Convert linux scope to InetScopeType */ unsigned long snmp_scope(int scope) { switch (scope) { case 0: return 14; /* global */ case 255: return 0; /* nowhere */ case 254: return 1; /* host */ case 253: return 2; /* link */ case 200: return 5; /* site */ default: return 0; } return 0; } void* snmp_header_list_table(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method, list dlist) { element e; void *scr; unsigned int target, current; if (header_simple_table(vp, name, length, exact, var_len, write_method, -1)) return NULL; if (LIST_ISEMPTY(dlist)) return NULL; target = name[*length - 1]; current = 0; for (e = LIST_HEAD(dlist); e; ELEMENT_NEXT(e)) { scr = ELEMENT_DATA(e); current++; if (current == target) /* Exact match */ return scr; if (current < target) /* No match found yet */ continue; if (exact) /* No exact match found */ return NULL; /* current is the best match */ name[*length - 1] = current; return scr; } /* No macth found at end */ return NULL; } #define SNMP_KEEPALIVEDVERSION 1 #define SNMP_ROUTERID 2 #define SNMP_MAIL_SMTPSERVERADDRESSTYPE 3 #define SNMP_MAIL_SMTPSERVERADDRESS 4 #define SNMP_MAIL_SMTPSERVERTIMEOUT 5 #define SNMP_MAIL_EMAILFROM 6 #define SNMP_MAIL_EMAILADDRESS 7 #define SNMP_TRAPS 8 #define SNMP_LINKBEAT 9 static u_char* snmp_scalar(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static unsigned long long_ret; static char version[] = VERSION_STRING; if (header_generic(vp, name, length, exact, var_len, write_method)) return NULL; switch (vp->magic) { case SNMP_KEEPALIVEDVERSION: *var_len = sizeof(version) - 2; return (u_char *)version; case SNMP_ROUTERID: if (!global_data->router_id) return NULL; *var_len = strlen(global_data->router_id); return (u_char *)global_data->router_id; case SNMP_MAIL_SMTPSERVERADDRESSTYPE: long_ret = (global_data->smtp_server.ss_family == AF_INET6)?2:1; return (u_char *)&long_ret; case SNMP_MAIL_SMTPSERVERADDRESS: if (global_data->smtp_server.ss_family == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&global_data->smtp_server; *var_len = 16; return (u_char *)&addr6->sin6_addr; } else { struct sockaddr_in *addr4 = (struct sockaddr_in *)&global_data->smtp_server; *var_len = 4; return (u_char *)&addr4->sin_addr; } return NULL; case SNMP_MAIL_SMTPSERVERTIMEOUT: long_ret = global_data->smtp_connection_to / TIMER_HZ; return (u_char *)&long_ret; case SNMP_MAIL_EMAILFROM: if (!global_data->email_from) return NULL; *var_len = strlen(global_data->email_from); return (u_char *)global_data->email_from; case SNMP_TRAPS: long_ret = global_data->enable_traps?1:2; return (u_char *)&long_ret; case SNMP_LINKBEAT: long_ret = global_data->linkbeat_use_polling?2:1; return (u_char *)&long_ret; default: break; } return NULL; } static u_char* snmp_mail(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { char *m; if ((m = (char *)snmp_header_list_table(vp, name, length, exact, var_len, write_method, global_data->email)) == NULL) return NULL; switch (vp->magic) { case SNMP_MAIL_EMAILADDRESS: *var_len = strlen(m); return (u_char *)m; default: break; } return NULL; } static oid global_oid[] = GLOBAL_OID; static struct variable8 global_vars[] = { /* version */ {SNMP_KEEPALIVEDVERSION, ASN_OCTET_STR, RONLY, snmp_scalar, 1, {1}}, /* routerId */ {SNMP_ROUTERID, ASN_OCTET_STR, RONLY, snmp_scalar, 1, {2}}, /* mail */ {SNMP_MAIL_SMTPSERVERADDRESSTYPE, ASN_INTEGER, RONLY, snmp_scalar, 2, {3, 1}}, {SNMP_MAIL_SMTPSERVERADDRESS, ASN_OCTET_STR, RONLY, snmp_scalar, 2, {3, 2}}, {SNMP_MAIL_SMTPSERVERTIMEOUT, ASN_UNSIGNED, RONLY, snmp_scalar, 2, {3, 3}}, {SNMP_MAIL_EMAILFROM, ASN_OCTET_STR, RONLY, snmp_scalar, 2, {3, 4}}, /* emailTable */ {SNMP_MAIL_EMAILADDRESS, ASN_OCTET_STR, RONLY, snmp_mail, 4, {3, 5, 1, 2}}, /* trapEnable */ {SNMP_TRAPS, ASN_INTEGER, RONLY, snmp_scalar, 1, {4}}, /* linkBeat */ {SNMP_LINKBEAT, ASN_INTEGER, RONLY, snmp_scalar, 1, {5}}, }; static int snmp_setup_session_cb(int majorID, int minorID, void *serverarg, void *clientarg) { netsnmp_session *sess = serverarg; if (serverarg == NULL) return 0; /* Because ping are done synchronously, we do everything to avoid to block too long. Better disconnect from the master agent than waiting for him... */ sess->timeout = ONE_SEC / 3; sess->retries = 0; return 0; } void snmp_agent_init(oid *myoid, int len, char *name, struct variable *variables, int varsize, int varlen) { log_message(LOG_INFO, "Starting SNMP subagent"); netsnmp_enable_subagent(); snmp_disable_log(); snmp_enable_calllog(); snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING, snmp_keepalived_log, NULL); /* Do not handle persistent states */ netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PERSIST_STATE, TRUE); /* Do not load any MIB */ setenv("MIBS", "", 1); /* We also register a callback to modify default timeout and retries value. */ snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SESSION_INIT, snmp_setup_session_cb, NULL); init_agent(name); /* Ping AgentX less often than every 15 seconds: pinging can block keepalived. We check every 2 minutes. */ netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL, 120); if (register_mib(name, (struct variable *) variables, varsize, varlen, myoid, len) != MIB_REGISTERED_OK) log_message(LOG_WARNING, "Unable to register MIB"); register_mib("Keepalived", (struct variable *) global_vars, sizeof(struct variable8), sizeof(global_vars)/sizeof(struct variable8), global_oid, OID_LENGTH(global_oid)); init_snmp(name); register_sysORTable(global_oid, OID_LENGTH(global_oid) - 1, "The MIB module for Keepalived"); } void snmp_agent_close(oid *myoid, int len, char *name) { unregister_sysORTable(myoid, len); snmp_shutdown(name); } keepalived-1.2.13/keepalived/core/daemon.c0000664000175000017500000000372112211121152020164 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Main program structure. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include #include "daemon.h" #include "logger.h" #include "utils.h" /* Daemonization function coming from zebra source code */ pid_t xdaemon(int nochdir, int noclose, int exitflag) { pid_t pid; int ret; /* In case of fork is error. */ pid = fork(); if (pid < 0) { log_message(LOG_INFO, "xdaemon: fork error"); return -1; } /* In case of this is parent process. */ if (pid != 0) { if (!exitflag) exit(0); else return pid; } /* Become session leader and get pid. */ pid = setsid(); if (pid < -1) { log_message(LOG_INFO, "xdaemon: setsid error"); return -1; } /* Change directory to root. */ if (!nochdir) { ret = chdir("/"); if (ret < 0) { log_message(LOG_INFO, "xdaemon: chdir error"); } } /* File descriptor close. */ if (!noclose) { int fd; fd = open("/dev/null", O_RDWR, 0); if (fd != -1) { dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); if (fd > 2) close(fd); } } umask(0); return 0; } keepalived-1.2.13/keepalived/core/layer4.c0000644000175000017500000001034412334072037020133 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Layer4 checkers handling. Register worker threads & * upper layer checkers. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "layer4.h" #include "utils.h" #include "logger.h" enum connect_result tcp_bind_connect(int fd, conn_opts_t *co) { struct linger li = { 0 }; socklen_t addrlen; int ret; int val; struct sockaddr_storage *addr = &co->dst; struct sockaddr_storage *bind_addr = &co->bindto; /* free the tcp port after closing the socket descriptor */ li.l_onoff = 1; li.l_linger = 0; setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof (struct linger)); /* Make socket non-block. */ val = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, val | O_NONBLOCK); #ifdef _WITH_SO_MARK_ if (co->fwmark) { if (setsockopt (fd, SOL_SOCKET, SO_MARK, &co->fwmark, sizeof (co->fwmark)) < 0) { log_message(LOG_ERR, "Error setting fwmark %d to socket: %s", co->fwmark, strerror(errno)); return connect_error; } } #endif /* Bind socket */ if (((struct sockaddr *) bind_addr)->sa_family != AF_UNSPEC) { addrlen = sizeof(*bind_addr); if (bind(fd, (struct sockaddr *) bind_addr, addrlen) != 0) return connect_error; } /* Set remote IP and connect */ addrlen = sizeof(*addr); ret = connect(fd, (struct sockaddr *) addr, addrlen); /* Immediate success */ if (ret == 0) { fcntl(fd, F_SETFL, val); return connect_success; } /* If connect is in progress then return 1 else it's real error. */ if (ret < 0) { if (errno != EINPROGRESS) return connect_error; } /* restore previous fd args */ fcntl(fd, F_SETFL, val); return connect_in_progress; } enum connect_result tcp_connect(int fd, struct sockaddr_storage *addr) { conn_opts_t co; memset(&co, 0, sizeof(co)); co.dst = *addr; return tcp_bind_connect(fd, &co); } enum connect_result tcp_socket_state(int fd, thread_t * thread, int (*func) (thread_t *)) { int status; socklen_t addrlen; int ret = 0; timeval_t timer_min; /* Handle connection timeout */ if (thread->type == THREAD_WRITE_TIMEOUT) { close(thread->u.fd); return connect_timeout; } /* Check file descriptor */ addrlen = sizeof(status); if (getsockopt(thread->u.fd, SOL_SOCKET, SO_ERROR, (void *) &status, &addrlen) < 0) ret = errno; /* Connection failed !!! */ if (ret) { close(thread->u.fd); return connect_error; } /* If status = 0, TCP connection to remote host is established. * Otherwise register checker thread to handle connection in progress, * and other error code until connection is established. * Recompute the write timeout (or pending connection). */ if (status == EINPROGRESS) { timer_min = timer_sub_now(thread->sands); thread_add_write(thread->master, func, THREAD_ARG(thread), thread->u.fd, timer_long(timer_min)); return connect_in_progress; } else if (status != 0) { close(thread->u.fd); return connect_error; } return connect_success; } int tcp_connection_state(int fd, enum connect_result status, thread_t * thread, int (*func) (thread_t *), long timeout) { checker_t *checker; checker = THREAD_ARG(thread); switch (status) { case connect_success: thread_add_write(thread->master, func, checker, fd, timeout); return 0; /* Checking non-blocking connect, we wait until socket is writable */ case connect_in_progress: thread_add_write(thread->master, func, checker, fd, timeout); return 0; default: return 1; } } keepalived-1.2.13/keepalived/core/global_parser.c0000664000175000017500000000743212261333232021551 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Configuration file parser/reader. Place into the dynamic * data structure representation the conf file representing * the loadbalanced server pool. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include #include "global_parser.h" #include "global_data.h" #include "check_data.h" #include "parser.h" #include "memory.h" #include "smtp.h" #include "utils.h" #include "logger.h" /* data handlers */ /* Global def handlers */ static void use_polling_handler(vector_t *strvec) { global_data->linkbeat_use_polling = 1; } static void routerid_handler(vector_t *strvec) { FREE_PTR(global_data->router_id); global_data->router_id = set_value(strvec); } static void plugin_handler(vector_t *strvec) { global_data->plugin_dir = set_value(strvec); } static void emailfrom_handler(vector_t *strvec) { FREE_PTR(global_data->email_from); global_data->email_from = set_value(strvec); } static void smtpto_handler(vector_t *strvec) { global_data->smtp_connection_to = atoi(vector_slot(strvec, 1)) * TIMER_HZ; } static void smtpip_handler(vector_t *strvec) { inet_stosockaddr(vector_slot(strvec, 1), SMTP_PORT_STR, &global_data->smtp_server); } static void email_handler(vector_t *strvec) { vector_t *email_vec = read_value_block(); int i; char *str; for (i = 0; i < vector_size(email_vec); i++) { str = vector_slot(email_vec, i); alloc_email(str); } free_strvec(email_vec); } static void vrrp_mcast_group4_handler(vector_t *strvec) { struct sockaddr_storage *mcast = &global_data->vrrp_mcast_group4; int ret; ret = inet_stosockaddr(vector_slot(strvec, 1), 0, mcast); if (ret < 0) { log_message(LOG_ERR, "Configuration error: Cant parse vrrp_mcast_group4 [%s]. Skipping" , vector_slot(strvec, 1)); } } static void vrrp_mcast_group6_handler(vector_t *strvec) { struct sockaddr_storage *mcast = &global_data->vrrp_mcast_group6; int ret; ret = inet_stosockaddr(vector_slot(strvec, 1), 0, mcast); if (ret < 0) { log_message(LOG_ERR, "Configuration error: Cant parse vrrp_mcast_group6 [%s]. Skipping" , vector_slot(strvec, 1)); } } #ifdef _WITH_SNMP_ static void trap_handler(vector_t *strvec) { global_data->enable_traps = 1; } #endif void global_init_keywords(void) { /* global definitions mapping */ install_keyword_root("linkbeat_use_polling", use_polling_handler); install_keyword_root("global_defs", NULL); install_keyword("router_id", &routerid_handler); install_keyword("plugin_dir", &plugin_handler); install_keyword("notification_email_from", &emailfrom_handler); install_keyword("smtp_server", &smtpip_handler); install_keyword("smtp_connect_timeout", &smtpto_handler); install_keyword("notification_email", &email_handler); install_keyword("vrrp_mcast_group4", &vrrp_mcast_group4_handler); install_keyword("vrrp_mcast_group6", &vrrp_mcast_group6_handler); #ifdef _WITH_SNMP_ install_keyword("enable_traps", &trap_handler); #endif } keepalived-1.2.13/keepalived/check/0000775000175000017500000000000012334417517016722 5ustar acassenacassenkeepalived-1.2.13/keepalived/check/check_snmp.c0000664000175000017500000010247312211376212021175 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: SNMP agent * * Author: Vincent Bernat * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "check_data.h" #include "check_snmp.h" #include "list.h" #include "ipvswrapper.h" #include "ipwrapper.h" #include "global_data.h" static u_char* check_snmp_vsgroup(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { virtual_server_group_t *g; if ((g = (virtual_server_group_t *) snmp_header_list_table(vp, name, length, exact, var_len, write_method, check_data->vs_group)) == NULL) return NULL; switch (vp->magic) { case CHECK_SNMP_VSGROUPNAME: *var_len = strlen(g->gname); return (u_char *)g->gname; default: break; } return NULL; } static u_char* check_snmp_vsgroupmember(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static unsigned long long_ret; static uint32_t ip; static struct in6_addr ip6; oid *target, current[2], best[2]; int result, target_len; int curgroup = 0, curentry; element e1, e2; virtual_server_group_t *group; virtual_server_group_entry_t *e, *be = NULL; int state; list l; if ((result = snmp_oid_compare(name, *length, vp->name, vp->namelen)) < 0) { memcpy(name, vp->name, sizeof(oid) * vp->namelen); *length = vp->namelen; } *write_method = 0; *var_len = sizeof(long); if (LIST_ISEMPTY(check_data->vs_group)) return NULL; /* We search the best match: equal if exact, the lower OID in the set of the OID strictly superior to the target otherwise. */ best[0] = best[1] = MAX_SUBID; /* Our best match */ target = &name[vp->namelen]; /* Our target match */ target_len = *length - vp->namelen; for (e1 = LIST_HEAD(check_data->vs_group); e1; ELEMENT_NEXT(e1)) { group = ELEMENT_DATA(e1); curgroup++; curentry = 0; if (target_len && (curgroup < target[0])) continue; /* Optimization: cannot be part of our set */ if (be) break; /* Optimization: cannot be the lower anymore */ state = STATE_VSGM_FWMARK; while (state != STATE_VSGM_END) { switch (state) { case STATE_VSGM_FWMARK: l = group->vfwmark; break; case STATE_VSGM_ADDRESS: l = group->addr_ip; break; case STATE_VSGM_RANGE: l = group->range; break; default: /* Dunno? */ return NULL; } state++; if (LIST_ISEMPTY(l)) continue; for (e2 = LIST_HEAD(l); e2; ELEMENT_NEXT(e2)) { e = ELEMENT_DATA(e2); curentry++; /* We build our current match */ current[0] = curgroup; current[1] = curentry; /* And compare it to our target match */ if ((result = snmp_oid_compare(current, 2, target, target_len)) < 0) continue; if ((result == 0) && !exact) continue; if (result == 0) { /* Got an exact match and asked for it */ be = e; goto vsgmember_found; } if (snmp_oid_compare(current, 2, best, 2) < 0) { /* This is our best match */ memcpy(best, current, sizeof(oid) * 2); be = e; goto vsgmember_be_found; } } } } if (be == NULL) /* No best match */ return NULL; if (exact) /* No exact match */ return NULL; vsgmember_be_found: /* Let's use our best match */ memcpy(target, best, sizeof(oid) * 2); *length = vp->namelen + 2; vsgmember_found: switch (vp->magic) { case CHECK_SNMP_VSGROUPMEMBERTYPE: if (be->vfwmark) long_ret = 1; else if (be->range) long_ret = 3; else long_ret = 2; return (u_char *)&long_ret; case CHECK_SNMP_VSGROUPMEMBERFWMARK: if (!be->vfwmark) break; long_ret = be->vfwmark; return (u_char *)&long_ret; case CHECK_SNMP_VSGROUPMEMBERADDRTYPE: if (be->vfwmark) break; long_ret = (be->addr.ss_family == AF_INET6) ? 2:1; return (u_char *)&long_ret; case CHECK_SNMP_VSGROUPMEMBERADDRESS: if (be->vfwmark || be->range) break; RETURN_IP46ADDRESS(be); break; case CHECK_SNMP_VSGROUPMEMBERADDR1: if (!be->range) break; RETURN_IP46ADDRESS(be); break; case CHECK_SNMP_VSGROUPMEMBERADDR2: if (!be->range) break; if (be->addr.ss_family == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&be->addr; *var_len = 16; memcpy(&ip6, &addr6->sin6_addr, sizeof(ip6)); ip6.s6_addr32[3] &= htonl(0xFFFFFF00); ip6.s6_addr32[3] += htonl(be->range); return (u_char *)&ip6; } else { struct sockaddr_in *addr4 = (struct sockaddr_in *)&be->addr; *var_len = 4; ip = (*(u_int32_t *)&addr4->sin_addr) & htonl(0xFFFFFF00); ip += htonl(be->range); return (u_char *)&ip; } break; case CHECK_SNMP_VSGROUPMEMBERPORT: if (be->vfwmark) break; long_ret = htons(inet_sockaddrport(&be->addr)); return (u_char *)&long_ret; default: return NULL; } /* If we are here, we asked for a non existent data. Try the next one. */ if (!exact && (name[*length-1] < MAX_SUBID)) return check_snmp_vsgroupmember(vp, name, length, exact, var_len, write_method); return NULL; } static u_char* check_snmp_virtualserver(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static unsigned long long_ret; #ifdef _KRNL_2_6_ static U64 counter64_ret; #endif virtual_server_t *v; element e; if ((v = (virtual_server_t *) snmp_header_list_table(vp, name, length, exact, var_len, write_method, check_data->vs)) == NULL) return NULL; switch (vp->magic) { case CHECK_SNMP_VSTYPE: if (v->vsgname) long_ret = 3; else if (v->vfwmark) long_ret = 1; else long_ret = 2; return (u_char*)&long_ret; case CHECK_SNMP_VSNAMEGROUP: if (!v->vsgname) break; *var_len = strlen(v->vsgname); return (u_char*)v->vsgname; case CHECK_SNMP_VSFWMARK: if (!v->vfwmark) break; long_ret = v->vfwmark; return (u_char*)&long_ret; case CHECK_SNMP_VSADDRTYPE: if (v->vfwmark || v->vsgname) break; long_ret = (v->addr.ss_family == AF_INET6) ? 2:1; return (u_char*)&long_ret; case CHECK_SNMP_VSADDRESS: if (v->vfwmark || v->vsgname) break; RETURN_IP46ADDRESS(v); break; case CHECK_SNMP_VSPORT: if (v->vfwmark || v->vsgname) break; long_ret = htons(inet_sockaddrport(&v->addr)); return (u_char *)&long_ret; case CHECK_SNMP_VSPROTOCOL: long_ret = (v->service_type == IPPROTO_TCP)?1:2; return (u_char*)&long_ret; case CHECK_SNMP_VSLOADBALANCINGALGO: if (strncmp(v->sched, "rr", SCHED_MAX_LENGTH) == 0) long_ret = 1; else if (strncmp(v->sched, "wrr", SCHED_MAX_LENGTH) == 0) long_ret = 2; else if (strncmp(v->sched, "lc", SCHED_MAX_LENGTH) == 0) long_ret = 3; else if (strncmp(v->sched, "wlc", SCHED_MAX_LENGTH) == 0) long_ret = 4; else if (strncmp(v->sched, "lblc", SCHED_MAX_LENGTH) == 0) long_ret = 5; else if (strncmp(v->sched, "lblcr", SCHED_MAX_LENGTH) == 0) long_ret = 6; else if (strncmp(v->sched, "dh", SCHED_MAX_LENGTH) == 0) long_ret = 7; else if (strncmp(v->sched, "sh", SCHED_MAX_LENGTH) == 0) long_ret = 8; else if (strncmp(v->sched, "sed", SCHED_MAX_LENGTH) == 0) long_ret = 9; else if (strncmp(v->sched, "nq", SCHED_MAX_LENGTH) == 0) long_ret = 10; else long_ret = 99; return (u_char*)&long_ret; case CHECK_SNMP_VSLOADBALANCINGKIND: long_ret = 0; switch (v->loadbalancing_kind) { #ifdef _WITH_LVS_ #ifdef _KRNL_2_2_ case 0: long_ret = 1; break; case IP_MASQ_F_VS_DROUTE: long_ret = 2; break; case IP_MASQ_F_VS_TUNNEL: long_ret = 3; break; #else case IP_VS_CONN_F_MASQ: long_ret = 1; break; case IP_VS_CONN_F_DROUTE: long_ret = 2; break; case IP_VS_CONN_F_TUNNEL: long_ret = 3; break; #endif #endif } if (!long_ret) break; return (u_char*)&long_ret; case CHECK_SNMP_VSSTATUS: long_ret = v->alive?1:2; return (u_char*)&long_ret; case CHECK_SNMP_VSVIRTUALHOST: if (!v->virtualhost) break; *var_len = strlen(v->virtualhost); return (u_char*)v->virtualhost; case CHECK_SNMP_VSPERSIST: long_ret = (atol(v->timeout_persistence) > 0)?1:2; return (u_char*)&long_ret; case CHECK_SNMP_VSPERSISTTIMEOUT: if (atol(v->timeout_persistence) <= 0) break; long_ret = atol(v->timeout_persistence); return (u_char*)&long_ret; case CHECK_SNMP_VSPERSISTGRANULARITY: if (atol(v->timeout_persistence) <= 0) break; if (!v->granularity_persistence) break; *var_len = 4; return (u_char*)&v->granularity_persistence; case CHECK_SNMP_VSDELAYLOOP: if (v->delay_loop >= TIMER_MAX_SEC) long_ret = v->delay_loop/TIMER_HZ; else long_ret = v->delay_loop; return (u_char*)&long_ret; case CHECK_SNMP_VSHASUSPEND: long_ret = v->ha_suspend?1:2; return (u_char*)&long_ret; case CHECK_SNMP_VSOPS: long_ret = v->ops?1:2; return (u_char*)&long_ret; case CHECK_SNMP_VSALPHA: long_ret = v->alpha?1:2; return (u_char*)&long_ret; case CHECK_SNMP_VSOMEGA: long_ret = v->omega?1:2; return (u_char*)&long_ret; case CHECK_SNMP_VSQUORUM: long_ret = v->quorum; return (u_char*)&long_ret; case CHECK_SNMP_VSQUORUMSTATUS: long_ret = v->quorum_state?1:2; return (u_char*)&long_ret; case CHECK_SNMP_VSQUORUMUP: if (!v->quorum_up) break; *var_len = strlen(v->quorum_up); return (u_char*)v->quorum_up; case CHECK_SNMP_VSQUORUMDOWN: if (!v->quorum_down) break; *var_len = strlen(v->quorum_down); return (u_char*)v->quorum_down; case CHECK_SNMP_VSHYSTERESIS: long_ret = v->hysteresis; return (u_char*)&long_ret; case CHECK_SNMP_VSREALTOTAL: if (LIST_ISEMPTY(v->rs)) long_ret = 0; else long_ret = LIST_SIZE(v->rs); return (u_char*)&long_ret; case CHECK_SNMP_VSREALUP: long_ret = 0; if (!LIST_ISEMPTY(v->rs)) for (e = LIST_HEAD(v->rs); e; ELEMENT_NEXT(e)) if (((real_server_t *)ELEMENT_DATA(e))->alive) long_ret++; return (u_char*)&long_ret; #if defined(_KRNL_2_6_) && defined(_WITH_LVS_) case CHECK_SNMP_VSSTATSCONNS: ipvs_update_stats(v); long_ret = v->stats.conns; return (u_char*)&long_ret; case CHECK_SNMP_VSSTATSINPKTS: ipvs_update_stats(v); long_ret = v->stats.inpkts; return (u_char*)&long_ret; case CHECK_SNMP_VSSTATSOUTPKTS: ipvs_update_stats(v); long_ret = v->stats.outpkts; return (u_char*)&long_ret; case CHECK_SNMP_VSSTATSINBYTES: ipvs_update_stats(v); counter64_ret.low = v->stats.inbytes & 0xffffffff; counter64_ret.high = v->stats.inbytes >> 32; *var_len = sizeof(U64); return (u_char*)&counter64_ret; case CHECK_SNMP_VSSTATSOUTBYTES: ipvs_update_stats(v); counter64_ret.low = v->stats.outbytes & 0xffffffff; counter64_ret.high = v->stats.outbytes >> 32; *var_len = sizeof(U64); return (u_char*)&counter64_ret; case CHECK_SNMP_VSRATECPS: ipvs_update_stats(v); long_ret = v->stats.cps; return (u_char*)&long_ret; case CHECK_SNMP_VSRATEINPPS: ipvs_update_stats(v); long_ret = v->stats.inpps; return (u_char*)&long_ret; case CHECK_SNMP_VSRATEOUTPPS: ipvs_update_stats(v); long_ret = v->stats.outpps; return (u_char*)&long_ret; case CHECK_SNMP_VSRATEINBPS: ipvs_update_stats(v); long_ret = v->stats.inbps; return (u_char*)&long_ret; case CHECK_SNMP_VSRATEOUTBPS: ipvs_update_stats(v); long_ret = v->stats.outbps; return (u_char*)&long_ret; #endif default: return NULL; } if (!exact && (name[*length-1] < MAX_SUBID)) return check_snmp_virtualserver(vp, name, length, exact, var_len, write_method); return NULL; } static int check_snmp_realserver_weight(int action, u_char *var_val, u_char var_val_type, size_t var_val_len, u_char *statP, oid *name, size_t name_len) { element e1, e2; virtual_server_t *vs = NULL; real_server_t *rs = NULL; int ivs, irs; switch (action) { case RESERVE1: /* Check that the proposed value is acceptable */ if (var_val_type != ASN_INTEGER) return SNMP_ERR_WRONGTYPE; if (var_val_len > sizeof(long)) return SNMP_ERR_WRONGLENGTH; if ((long)(*var_val) < 0) return SNMP_ERR_WRONGVALUE; break; case RESERVE2: /* Check that we can find the instance. We should. */ case COMMIT: /* Find the instance */ if (name_len < 2) return SNMP_ERR_NOSUCHNAME; irs = name[name_len - 1]; ivs = name[name_len - 2]; if (LIST_ISEMPTY(check_data->vs)) return SNMP_ERR_NOSUCHNAME; for (e1 = LIST_HEAD(check_data->vs); e1; ELEMENT_NEXT(e1)) { vs = ELEMENT_DATA(e1); if (--ivs == 0) { if (LIST_ISEMPTY(vs->rs)) return SNMP_ERR_NOSUCHNAME; if (vs->s_svr) { /* We don't want to set weight of sorry server */ rs = NULL; if (--irs == 0) break; } for (e2 = LIST_HEAD(vs->rs); e2; ELEMENT_NEXT(e2)) { rs = ELEMENT_DATA(e2); if (--irs == 0) break; } break; } } /* Did not find a RS or this is a sorry server (this should not happen) */ if (!rs) return SNMP_ERR_NOSUCHNAME; if (action == RESERVE2) break; /* Commit: change values. There is no way to fail. */ update_svr_wgt((long)(*var_val), vs, rs); break; } return SNMP_ERR_NOERROR; } static u_char* check_snmp_realserver(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static unsigned long long_ret; #ifdef _KRNL_2_6_ static U64 counter64_ret; #endif oid *target, current[2], best[2]; int result, target_len; int curvirtual = 0, curreal; real_server_t *e = NULL, *be = NULL; element e1, e2 = NULL; virtual_server_t *vs, *bvs = NULL; int state; int type, btype; if ((result = snmp_oid_compare(name, *length, vp->name, vp->namelen)) < 0) { memcpy(name, vp->name, sizeof(oid) * vp->namelen); *length = vp->namelen; } *write_method = 0; *var_len = sizeof(long); if (LIST_ISEMPTY(check_data->vs)) return NULL; /* We search the best match: equal if exact, the lower OID in the set of the OID strictly superior to the target otherwise. */ best[0] = best[1] = MAX_SUBID; /* Our best match */ target = &name[vp->namelen]; /* Our target match */ target_len = *length - vp->namelen; for (e1 = LIST_HEAD(check_data->vs); e1; ELEMENT_NEXT(e1)) { vs = ELEMENT_DATA(e1); curvirtual++; curreal = 0; if (target_len && (curvirtual < target[0])) continue; /* Optimization: cannot be part of our set */ if (be) break; /* Optimization: cannot be the lower anymore */ state = STATE_RS_SORRY; while (state != STATE_RS_END) { switch (state) { case STATE_RS_SORRY: e = vs->s_svr; type = state++; break; case STATE_RS_REGULAR_FIRST: if (LIST_ISEMPTY(vs->rs)) { e = NULL; state = STATE_RS_END; break; } e2 = LIST_HEAD(vs->rs); e = ELEMENT_DATA(e2); type = state++; break; case STATE_RS_REGULAR_NEXT: type = state; ELEMENT_NEXT(e2); if (!e2) { e = NULL; state++; break; } e = ELEMENT_DATA(e2); break; default: /* Dunno? */ return NULL; } if (!e) continue; curreal++; /* We build our current match */ current[0] = curvirtual; current[1] = curreal; /* And compare it to our target match */ if ((result = snmp_oid_compare(current, 2, target, target_len)) < 0) continue; if ((result == 0) && !exact) continue; if (result == 0) { /* Got an exact match and asked for it */ be = e; bvs = vs; btype = type; goto real_found; } if (snmp_oid_compare(current, 2, best, 2) < 0) { /* This is our best match */ memcpy(best, current, sizeof(oid) * 2); be = e; bvs = vs; btype = type; goto real_be_found; } } } if (be == NULL) /* No best match */ return NULL; if (exact) /* No exact match */ return NULL; real_be_found: /* Let's use our best match */ memcpy(target, best, sizeof(oid) * 2); *length = vp->namelen + 2; real_found: switch (vp->magic) { case CHECK_SNMP_RSTYPE: long_ret = (btype == STATE_RS_SORRY)?2:1; return (u_char*)&long_ret; case CHECK_SNMP_RSADDRTYPE: long_ret = (be->addr.ss_family == AF_INET6) ? 2:1; return (u_char*)&long_ret; case CHECK_SNMP_RSADDRESS: RETURN_IP46ADDRESS(be); break; case CHECK_SNMP_RSPORT: long_ret = htons(inet_sockaddrport(&be->addr)); return (u_char *)&long_ret; case CHECK_SNMP_RSSTATUS: if (btype == STATE_RS_SORRY) break; long_ret = be->alive?1:2; return (u_char*)&long_ret; case CHECK_SNMP_RSWEIGHT: if (btype == STATE_RS_SORRY) break; long_ret = be->weight; *write_method = check_snmp_realserver_weight; return (u_char*)&long_ret; #ifdef _KRNL_2_6_ case CHECK_SNMP_RSUPPERCONNECTIONLIMIT: if (btype == STATE_RS_SORRY) break; if (!be->u_threshold) break; long_ret = be->u_threshold; return (u_char*)&long_ret; case CHECK_SNMP_RSLOWERCONNECTIONLIMIT: if (btype == STATE_RS_SORRY) break; if (!be->l_threshold) break; long_ret = be->l_threshold; return (u_char*)&long_ret; #endif case CHECK_SNMP_RSACTIONWHENDOWN: if (btype == STATE_RS_SORRY) break; long_ret = be->inhibit?2:1; return (u_char*)&long_ret; case CHECK_SNMP_RSNOTIFYUP: if (btype == STATE_RS_SORRY) break; if (!be->notify_up) break; *var_len = strlen(be->notify_up); return (u_char*)be->notify_up; case CHECK_SNMP_RSNOTIFYDOWN: if (btype == STATE_RS_SORRY) break; if (!be->notify_down) break; *var_len = strlen(be->notify_down); return (u_char*)be->notify_down; case CHECK_SNMP_RSFAILEDCHECKS: if (btype == STATE_RS_SORRY) break; if (LIST_ISEMPTY(be->failed_checkers)) long_ret = 0; else long_ret = LIST_SIZE(be->failed_checkers); return (u_char*)&long_ret; #if defined(_KRNL_2_6_) && defined(_WITH_LVS_) case CHECK_SNMP_RSSTATSCONNS: ipvs_update_stats(bvs); long_ret = be->stats.conns; return (u_char*)&long_ret; case CHECK_SNMP_RSSTATSACTIVECONNS: ipvs_update_stats(bvs); long_ret = be->activeconns; return (u_char*)&long_ret; case CHECK_SNMP_RSSTATSINACTIVECONNS: ipvs_update_stats(bvs); long_ret = be->inactconns; return (u_char*)&long_ret; case CHECK_SNMP_RSSTATSPERSISTENTCONNS: ipvs_update_stats(bvs); long_ret = be->persistconns; return (u_char*)&long_ret; case CHECK_SNMP_RSSTATSINPKTS: ipvs_update_stats(bvs); long_ret = be->stats.inpkts; return (u_char*)&long_ret; case CHECK_SNMP_RSSTATSOUTPKTS: ipvs_update_stats(bvs); long_ret = be->stats.outpkts; return (u_char*)&long_ret; case CHECK_SNMP_RSSTATSINBYTES: ipvs_update_stats(bvs); counter64_ret.low = be->stats.inbytes & 0xffffffff; counter64_ret.high = be->stats.inbytes >> 32; *var_len = sizeof(U64); return (u_char*)&counter64_ret; case CHECK_SNMP_RSSTATSOUTBYTES: ipvs_update_stats(bvs); counter64_ret.low = be->stats.outbytes & 0xffffffff; counter64_ret.high = be->stats.outbytes >> 32; *var_len = sizeof(U64); return (u_char*)&counter64_ret; case CHECK_SNMP_RSRATECPS: ipvs_update_stats(bvs); long_ret = be->stats.cps; return (u_char*)&long_ret; case CHECK_SNMP_RSRATEINPPS: ipvs_update_stats(bvs); long_ret = be->stats.inpps; return (u_char*)&long_ret; case CHECK_SNMP_RSRATEOUTPPS: ipvs_update_stats(bvs); long_ret = be->stats.outpps; return (u_char*)&long_ret; case CHECK_SNMP_RSRATEINBPS: ipvs_update_stats(bvs); long_ret = be->stats.inbps; return (u_char*)&long_ret; case CHECK_SNMP_RSRATEOUTBPS: ipvs_update_stats(bvs); long_ret = be->stats.outbps; return (u_char*)&long_ret; #endif default: return NULL; } /* If we are here, we asked for a non existent data. Try the next one. */ if (!exact && (name[*length-1] < MAX_SUBID)) return check_snmp_realserver(vp, name, length, exact, var_len, write_method); return NULL; } static oid check_oid[] = {CHECK_OID}; static struct variable8 check_vars[] = { /* virtualServerGroupTable */ {CHECK_SNMP_VSGROUPNAME, ASN_OCTET_STR, RONLY, check_snmp_vsgroup, 3, {1, 1, 2}}, /* virtualServerGroupMemberTable */ {CHECK_SNMP_VSGROUPMEMBERTYPE, ASN_INTEGER, RONLY, check_snmp_vsgroupmember, 3, {2, 1, 2}}, {CHECK_SNMP_VSGROUPMEMBERFWMARK, ASN_UNSIGNED, RONLY, check_snmp_vsgroupmember, 3, {2, 1, 3}}, {CHECK_SNMP_VSGROUPMEMBERADDRTYPE, ASN_INTEGER, RONLY, check_snmp_vsgroupmember, 3, {2, 1, 4}}, {CHECK_SNMP_VSGROUPMEMBERADDRESS, ASN_OCTET_STR, RONLY, check_snmp_vsgroupmember, 3, {2, 1, 5}}, {CHECK_SNMP_VSGROUPMEMBERADDR1, ASN_OCTET_STR, RONLY, check_snmp_vsgroupmember, 3, {2, 1, 6}}, {CHECK_SNMP_VSGROUPMEMBERADDR2, ASN_OCTET_STR, RONLY, check_snmp_vsgroupmember, 3, {2, 1, 7}}, {CHECK_SNMP_VSGROUPMEMBERPORT, ASN_UNSIGNED, RONLY, check_snmp_vsgroupmember, 3, {2, 1, 8}}, /* virtualServerTable */ {CHECK_SNMP_VSTYPE, ASN_INTEGER, RONLY, check_snmp_virtualserver, 3, {3, 1, 2}}, {CHECK_SNMP_VSNAMEGROUP, ASN_OCTET_STR, RONLY, check_snmp_virtualserver, 3, {3, 1, 3}}, {CHECK_SNMP_VSFWMARK, ASN_UNSIGNED, RONLY, check_snmp_virtualserver, 3, {3, 1, 4}}, {CHECK_SNMP_VSADDRTYPE, ASN_INTEGER, RONLY, check_snmp_virtualserver, 3, {3, 1, 5}}, {CHECK_SNMP_VSADDRESS, ASN_OCTET_STR, RONLY, check_snmp_virtualserver, 3, {3, 1, 6}}, {CHECK_SNMP_VSPORT, ASN_UNSIGNED, RONLY, check_snmp_virtualserver, 3, {3, 1, 7}}, {CHECK_SNMP_VSPROTOCOL, ASN_INTEGER, RONLY, check_snmp_virtualserver, 3, {3, 1, 8}}, {CHECK_SNMP_VSLOADBALANCINGALGO, ASN_INTEGER, RONLY, check_snmp_virtualserver, 3, {3, 1, 9}}, {CHECK_SNMP_VSLOADBALANCINGKIND, ASN_INTEGER, RONLY, check_snmp_virtualserver, 3, {3, 1, 10}}, {CHECK_SNMP_VSSTATUS, ASN_INTEGER, RONLY, check_snmp_virtualserver, 3, {3, 1, 11}}, {CHECK_SNMP_VSVIRTUALHOST, ASN_OCTET_STR, RONLY, check_snmp_virtualserver, 3, {3, 1, 12}}, {CHECK_SNMP_VSPERSIST, ASN_INTEGER, RONLY, check_snmp_virtualserver, 3, {3, 1, 13}}, {CHECK_SNMP_VSPERSISTTIMEOUT, ASN_UNSIGNED, RONLY, check_snmp_virtualserver, 3, {3, 1, 14}}, {CHECK_SNMP_VSPERSISTGRANULARITY, ASN_OCTET_STR, RONLY, check_snmp_virtualserver, 3, {3, 1, 15}}, {CHECK_SNMP_VSDELAYLOOP, ASN_UNSIGNED, RONLY, check_snmp_virtualserver, 3, {3, 1, 16}}, {CHECK_SNMP_VSHASUSPEND, ASN_INTEGER, RONLY, check_snmp_virtualserver, 3, {3, 1, 17}}, {CHECK_SNMP_VSOPS, ASN_INTEGER, RONLY, check_snmp_virtualserver, 3, {3, 1, 37}}, {CHECK_SNMP_VSALPHA, ASN_INTEGER, RONLY, check_snmp_virtualserver, 3, {3, 1, 18}}, {CHECK_SNMP_VSOMEGA, ASN_INTEGER, RONLY, check_snmp_virtualserver, 3, {3, 1, 19}}, {CHECK_SNMP_VSREALTOTAL, ASN_UNSIGNED, RONLY, check_snmp_virtualserver, 3, {3, 1, 20}}, {CHECK_SNMP_VSREALUP, ASN_UNSIGNED, RONLY, check_snmp_virtualserver, 3, {3, 1, 21}}, {CHECK_SNMP_VSQUORUM, ASN_UNSIGNED, RONLY, check_snmp_virtualserver, 3, {3, 1, 22}}, {CHECK_SNMP_VSQUORUMSTATUS, ASN_INTEGER, RONLY, check_snmp_virtualserver, 3, {3, 1, 23}}, {CHECK_SNMP_VSQUORUMUP, ASN_OCTET_STR, RONLY, check_snmp_virtualserver, 3, {3, 1, 24}}, {CHECK_SNMP_VSQUORUMDOWN, ASN_OCTET_STR, RONLY, check_snmp_virtualserver, 3, {3, 1, 25}}, {CHECK_SNMP_VSHYSTERESIS, ASN_UNSIGNED, RONLY, check_snmp_virtualserver, 3, {3, 1, 26}}, #if defined(_KRNL_2_6_) && defined(_WITH_LVS_) {CHECK_SNMP_VSSTATSCONNS, ASN_GAUGE, RONLY, check_snmp_virtualserver, 3, {3, 1, 27}}, {CHECK_SNMP_VSSTATSINPKTS, ASN_COUNTER, RONLY, check_snmp_virtualserver, 3, {3, 1, 28}}, {CHECK_SNMP_VSSTATSOUTPKTS, ASN_COUNTER, RONLY, check_snmp_virtualserver, 3, {3, 1, 29}}, {CHECK_SNMP_VSSTATSINBYTES, ASN_COUNTER64, RONLY, check_snmp_virtualserver, 3, {3, 1, 30}}, {CHECK_SNMP_VSSTATSOUTBYTES, ASN_COUNTER64, RONLY, check_snmp_virtualserver, 3, {3, 1, 31}}, {CHECK_SNMP_VSRATECPS, ASN_GAUGE, RONLY, check_snmp_virtualserver, 3, {3, 1, 32}}, {CHECK_SNMP_VSRATEINPPS, ASN_GAUGE, RONLY, check_snmp_virtualserver, 3, {3, 1, 33}}, {CHECK_SNMP_VSRATEOUTPPS, ASN_GAUGE, RONLY, check_snmp_virtualserver, 3, {3, 1, 34}}, {CHECK_SNMP_VSRATEINBPS, ASN_GAUGE, RONLY, check_snmp_virtualserver, 3, {3, 1, 35}}, {CHECK_SNMP_VSRATEOUTBPS, ASN_GAUGE, RONLY, check_snmp_virtualserver, 3, {3, 1, 36}}, #endif /* realServerTable */ {CHECK_SNMP_RSTYPE, ASN_INTEGER, RONLY, check_snmp_realserver, 3, {4, 1, 2}}, {CHECK_SNMP_RSADDRTYPE, ASN_INTEGER, RONLY, check_snmp_realserver, 3, {4, 1, 3}}, {CHECK_SNMP_RSADDRESS, ASN_OCTET_STR, RONLY, check_snmp_realserver, 3, {4, 1, 4}}, {CHECK_SNMP_RSPORT, ASN_UNSIGNED, RONLY, check_snmp_realserver, 3, {4, 1, 5}}, {CHECK_SNMP_RSSTATUS, ASN_INTEGER, RONLY, check_snmp_realserver, 3, {4, 1, 6}}, {CHECK_SNMP_RSWEIGHT, ASN_INTEGER, RWRITE, check_snmp_realserver, 3, {4, 1, 7}}, #ifdef _KRNL_2_6_ {CHECK_SNMP_RSUPPERCONNECTIONLIMIT, ASN_UNSIGNED, RONLY, check_snmp_realserver, 3, {4, 1, 8}}, {CHECK_SNMP_RSLOWERCONNECTIONLIMIT, ASN_UNSIGNED, RONLY, check_snmp_realserver, 3, {4, 1, 9}}, #endif {CHECK_SNMP_RSACTIONWHENDOWN, ASN_INTEGER, RONLY, check_snmp_realserver, 3, {4, 1, 10}}, {CHECK_SNMP_RSNOTIFYUP, ASN_OCTET_STR, RONLY, check_snmp_realserver, 3, {4, 1, 11}}, {CHECK_SNMP_RSNOTIFYDOWN, ASN_OCTET_STR, RONLY, check_snmp_realserver, 3, {4, 1, 12}}, {CHECK_SNMP_RSFAILEDCHECKS, ASN_UNSIGNED, RONLY, check_snmp_realserver, 3, {4, 1, 13}}, #if defined(_KRNL_2_6_) && defined(_WITH_LVS_) {CHECK_SNMP_RSSTATSCONNS, ASN_GAUGE, RONLY, check_snmp_realserver, 3, {4, 1, 14}}, {CHECK_SNMP_RSSTATSACTIVECONNS, ASN_GAUGE, RONLY, check_snmp_realserver, 3, {4, 1, 15}}, {CHECK_SNMP_RSSTATSINACTIVECONNS, ASN_GAUGE, RONLY, check_snmp_realserver, 3, {4, 1, 16}}, {CHECK_SNMP_RSSTATSPERSISTENTCONNS, ASN_GAUGE, RONLY, check_snmp_realserver, 3, {4, 1, 17}}, {CHECK_SNMP_RSSTATSINPKTS, ASN_COUNTER, RONLY, check_snmp_realserver, 3, {4, 1, 18}}, {CHECK_SNMP_RSSTATSOUTPKTS, ASN_COUNTER, RONLY, check_snmp_realserver, 3, {4, 1, 19}}, {CHECK_SNMP_RSSTATSINBYTES, ASN_COUNTER64, RONLY, check_snmp_realserver, 3, {4, 1, 20}}, {CHECK_SNMP_RSSTATSOUTBYTES, ASN_COUNTER64, RONLY, check_snmp_realserver, 3, {4, 1, 21}}, {CHECK_SNMP_RSRATECPS, ASN_GAUGE, RONLY, check_snmp_realserver, 3, {4, 1, 22}}, {CHECK_SNMP_RSRATEINPPS, ASN_GAUGE, RONLY, check_snmp_realserver, 3, {4, 1, 23}}, {CHECK_SNMP_RSRATEOUTPPS, ASN_GAUGE, RONLY, check_snmp_realserver, 3, {4, 1, 24}}, {CHECK_SNMP_RSRATEINBPS, ASN_GAUGE, RONLY, check_snmp_realserver, 3, {4, 1, 25}}, {CHECK_SNMP_RSRATEOUTBPS, ASN_GAUGE, RONLY, check_snmp_realserver, 3, {4, 1, 26}}, #endif }; void check_snmp_agent_init() { snmp_agent_init(check_oid, OID_LENGTH(check_oid), "Healthchecker", (struct variable *)check_vars, sizeof(struct variable8), sizeof(check_vars)/sizeof(struct variable8)); } void check_snmp_agent_close() { snmp_agent_close(check_oid, OID_LENGTH(check_oid), "Healthchecker"); } void check_snmp_rs_trap(real_server_t *rs, virtual_server_t *vs) { element e; /* OID of the notification */ oid notification_oid[] = { CHECK_OID, 5, 0, 1 }; size_t notification_oid_len = OID_LENGTH(notification_oid); /* OID for snmpTrapOID.0 */ oid objid_snmptrap[] = { SNMPTRAP_OID }; size_t objid_snmptrap_len = OID_LENGTH(objid_snmptrap); /* Other OID */ oid addrtype_oid[] = { CHECK_OID, 4, 1, 3 }; size_t addrtype_oid_len = OID_LENGTH(addrtype_oid); static unsigned long addrtype = 1; oid address_oid[] = { CHECK_OID, 4, 1, 4 }; size_t address_oid_len = OID_LENGTH(address_oid); oid port_oid[] = { CHECK_OID, 4, 1, 5 }; size_t port_oid_len = OID_LENGTH(port_oid); static unsigned long port; oid status_oid[] = { CHECK_OID, 4, 1, 6 }; size_t status_oid_len = OID_LENGTH(status_oid); static unsigned long status; oid vstype_oid[] = { CHECK_OID, 3, 1, 2 }; size_t vstype_oid_len = OID_LENGTH(vstype_oid); static unsigned long vstype; oid vsgroupname_oid[] = { CHECK_OID, 3, 1, 3 }; size_t vsgroupname_oid_len = OID_LENGTH(vsgroupname_oid); oid vsfwmark_oid[] = { CHECK_OID, 3, 1, 4 }; size_t vsfwmark_oid_len = OID_LENGTH(vsfwmark_oid); static unsigned long vsfwmark; oid vsaddrtype_oid[] = {CHECK_OID, 3, 1, 5 }; size_t vsaddrtype_oid_len = OID_LENGTH(vsaddrtype_oid); oid vsaddress_oid[] = {CHECK_OID, 3, 1, 6 }; size_t vsaddress_oid_len = OID_LENGTH(vsaddress_oid); oid vsport_oid[] = {CHECK_OID, 3, 1, 7 }; size_t vsport_oid_len = OID_LENGTH(vsport_oid); static unsigned long vsport; oid vsprotocol_oid[] = {CHECK_OID, 3, 1, 8 }; size_t vsprotocol_oid_len = OID_LENGTH(vsprotocol_oid); static unsigned long vsprotocol; oid realup_oid[] = {CHECK_OID, 3, 1, 21 }; size_t realup_oid_len = OID_LENGTH(realup_oid); static unsigned long realup; oid realtotal_oid[] = {CHECK_OID, 3, 1, 20 }; size_t realtotal_oid_len = OID_LENGTH(realtotal_oid); static unsigned long realtotal; oid quorumstatus_oid[] = {CHECK_OID, 3, 1, 23 }; size_t quorumstatus_oid_len = OID_LENGTH(quorumstatus_oid); static unsigned long quorumstatus; oid quorum_oid[] = {CHECK_OID, 3, 1, 22 }; size_t quorum_oid_len = OID_LENGTH(quorum_oid); static unsigned long quorum; oid routerId_oid[] = { KEEPALIVED_OID, 1, 2, 0 }; size_t routerId_oid_len = OID_LENGTH(routerId_oid); netsnmp_variable_list *notification_vars = NULL; if (!global_data->enable_traps) return; if (!rs) notification_oid[notification_oid_len - 1] = 2; /* Initialize data */ if (LIST_ISEMPTY(vs->rs)) realtotal = 0; else realtotal = LIST_SIZE(vs->rs); realup = 0; if (!LIST_ISEMPTY(vs->rs)) for (e = LIST_HEAD(vs->rs); e; ELEMENT_NEXT(e)) if (((real_server_t *)ELEMENT_DATA(e))->alive) realup++; /* snmpTrapOID */ snmp_varlist_add_variable(¬ification_vars, objid_snmptrap, objid_snmptrap_len, ASN_OBJECT_ID, (u_char *) notification_oid, notification_oid_len * sizeof(oid)); if (rs) { /* realServerAddrType */ addrtype = (rs->addr.ss_family == AF_INET6)?2:1; snmp_varlist_add_variable(¬ification_vars, addrtype_oid, addrtype_oid_len, ASN_INTEGER, (u_char *)&addrtype, sizeof(addrtype)); /* realServerAddress */ snmp_varlist_add_variable(¬ification_vars, address_oid, address_oid_len, ASN_OCTET_STR, (rs->addr.ss_family == AF_INET6)? ((u_char *)&((struct sockaddr_in6 *)&rs->addr)->sin6_addr): ((u_char *)&((struct sockaddr_in *)&rs->addr)->sin_addr), (rs->addr.ss_family == AF_INET6)?16:4); /* realServerPort */ port = htons(inet_sockaddrport(&rs->addr)); snmp_varlist_add_variable(¬ification_vars, port_oid, port_oid_len, ASN_UNSIGNED, (u_char *)&port, sizeof(port)); /* realServerStatus */ status = rs->alive?1:2; snmp_varlist_add_variable(¬ification_vars, status_oid, status_oid_len, ASN_INTEGER, (u_char *)&status, sizeof(status)); } /* virtualServerType */ if (vs->vsgname) vstype = 3; else if (vs->vfwmark) vstype = 1; else vstype = 2; snmp_varlist_add_variable(¬ification_vars, vstype_oid, vstype_oid_len, ASN_INTEGER, (u_char *)&vstype, sizeof(vstype)); if (vs->vsgname) { /* virtualServerNameOfGroup */ snmp_varlist_add_variable(¬ification_vars, vsgroupname_oid, vsgroupname_oid_len, ASN_OCTET_STR, (u_char *)vs->vsgname, strlen(vs->vsgname)); } else if (vs->vfwmark) { vsfwmark = vs->vfwmark; snmp_varlist_add_variable(¬ification_vars, vsfwmark_oid, vsfwmark_oid_len, ASN_UNSIGNED, (u_char *)&vsfwmark, sizeof(vsfwmark)); } else { addrtype = (vs->addr.ss_family == AF_INET6)?2:1; snmp_varlist_add_variable(¬ification_vars, vsaddrtype_oid, vsaddrtype_oid_len, ASN_INTEGER, (u_char *)&addrtype, sizeof(addrtype)); snmp_varlist_add_variable(¬ification_vars, vsaddress_oid, vsaddress_oid_len, ASN_OCTET_STR, (vs->addr.ss_family == AF_INET6)? ((u_char *)&((struct sockaddr_in6 *)&vs->addr)->sin6_addr): ((u_char *)&((struct sockaddr_in *)&vs->addr)->sin_addr), (vs->addr.ss_family == AF_INET6)?16:4); vsport = htons(inet_sockaddrport(&vs->addr)); snmp_varlist_add_variable(¬ification_vars, vsport_oid, vsport_oid_len, ASN_UNSIGNED, (u_char *)&vsport, sizeof(vsport)); } vsprotocol = (vs->service_type == IPPROTO_TCP)?1:2; snmp_varlist_add_variable(¬ification_vars, vsprotocol_oid, vsprotocol_oid_len, ASN_INTEGER, (u_char *)&vsprotocol, sizeof(vsprotocol)); if (!rs) { quorumstatus = vs->quorum_state?1:2; snmp_varlist_add_variable(¬ification_vars, quorumstatus_oid, quorumstatus_oid_len, ASN_INTEGER, (u_char *)&quorumstatus, sizeof(quorumstatus)); quorum = vs->quorum; snmp_varlist_add_variable(¬ification_vars, quorum_oid, quorum_oid_len, ASN_UNSIGNED, (u_char *)&quorum, sizeof(quorum)); } snmp_varlist_add_variable(¬ification_vars, realup_oid, realup_oid_len, ASN_UNSIGNED, (u_char *)&realup, sizeof(realup)); snmp_varlist_add_variable(¬ification_vars, realtotal_oid, realtotal_oid_len, ASN_UNSIGNED, (u_char *)&realtotal, sizeof(realtotal)); /* routerId */ snmp_varlist_add_variable(¬ification_vars, routerId_oid, routerId_oid_len, ASN_OCTET_STR, (u_char *)global_data->router_id, strlen(global_data->router_id)); send_v2trap(notification_vars); snmp_free_varbind(notification_vars); } void check_snmp_quorum_trap(virtual_server_t *vs) { check_snmp_rs_trap(NULL, vs); } keepalived-1.2.13/keepalived/check/Makefile.in0000644000175000017500000000602512334072037020762 0ustar acassenacassen# Makefile # # Keepalived OpenSource project. # # Copyright (C) 2001-2012 Alexandre Cassen, CC = @CC@ SNMP_FLAG = @SNMP_SUPPORT@ INCLUDES = -I../include -I../../lib CFLAGS = @CFLAGS@ @CPPFLAGS@ $(INCLUDES) \ -Wall -Wunused -Wstrict-prototypes DEFS = -D@KERN@ -D@IPVS_SUPPORT@ -D@IPVS_SYNCD@ -D@VRRP_SUPPORT@ -D@SNMP_SUPPORT@ -D@SO_MARK_SUPPORT@ @DFLAGS@ COMPILE = $(CC) $(CFLAGS) $(DEFS) OBJS = check_daemon.o check_data.o check_parser.o \ check_api.o check_tcp.o check_http.o check_ssl.o \ check_smtp.o check_misc.o ipwrapper.o ipvswrapper.o ifeq ($(SNMP_FLAG),_WITH_SNMP_) OBJS += check_snmp.o endif HEADERS = $(OBJS:.o=.h) .c.o: $(COMPILE) -c $< all: $(OBJS) clean: rm -f *.a *.o *~ distclean: clean rm -f Makefile check_daemon.o: check_daemon.c ../include/check_daemon.h \ ../include/check_parser.h ../include/check_data.h ../include/check_api.h \ ../include/global_data.h ../include/ipwrapper.h ../include/ipwrapper.h \ ../include/pidfile.h ../include/daemon.h ../../lib/list.h ../../lib/memory.h \ ../../lib/parser.h ../../lib/signals.h ../include/vrrp_netlink.h \ ../include/vrrp_if.h ../include/snmp.h ../include/check_snmp.h check_data.o: check_data.c ../include/check_data.h \ ../include/check_api.h ../../lib/memory.h ../../lib/utils.h check_parser.o: check_parser.c ../include/check_parser.h \ ../include/check_data.h ../include/check_api.h ../include/global_data.h \ ../include/global_parser.h ../../lib/parser.h ../../lib/memory.h \ ../../lib/utils.h check_api.o: check_api.c ../include/check_api.h ../../lib/parser.h \ ../../lib/memory.h ../../lib/utils.h ../include/check_misc.h \ ../include/check_tcp.h ../include/check_http.h ../include/check_ssl.h check_tcp.o: check_tcp.c ../include/check_tcp.h ../include/check_api.h \ ../../lib/memory.h ../include/ipwrapper.h ../include/layer4.h \ ../include/smtp.h ../../lib/utils.h ../../lib/parser.h check_http.o: check_http.c ../include/check_http.h ../include/check_ssl.h \ ../include/check_api.h ../../lib/memory.h ../../lib/parser.h \ ../../lib/utils.h check_ssl.o: check_ssl.c ../include/check_ssl.h ../include/check_api.h \ ../../lib/memory.h ../../lib/parser.h ../include/smtp.h \ ../../lib/utils.h check_smtp.o: check_smtp.c ../include/check_smtp.h ../include/check_api.h \ ../../lib/memory.h ../include/ipwrapper.h ../include/smtp.h \ ../../lib/utils.h ../../lib/notify.h ../../lib/parser.h ../include/daemon.h check_misc.o: check_misc.c ../include/check_misc.h ../include/check_api.h \ ../../lib/memory.h ../include/ipwrapper.h ../include/smtp.h \ ../../lib/utils.h ../../lib/notify.h ../../lib/parser.h ../include/daemon.h ipwrapper.o: ipwrapper.c ../include/ipwrapper.h ../../lib/memory.h \ ../../lib/utils.h ../../lib/notify.h ../include/snmp.h ../include/check_snmp.h ipvswrapper.o: ipvswrapper.c ../include/ipvswrapper.h ../../lib/utils.h \ ../../lib/memory.h check_snmp.o: check_snmp.c ../include/check_snmp.h ../include/check_data.h \ ../../lib/list.h ../include/ipvswrapper.h ../include/ipwrapper.h ../include/global_data.h keepalived-1.2.13/keepalived/check/check_ssl.c0000644000175000017500000001753012334072037021022 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: SSL GET CHECK. Perform an ssl get query to a specified * url, compute a MD5 over this result and match it to the * expected value. * * Authors: Alexandre Cassen, * Jan Holmberg, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include #include "check_ssl.h" #include "check_api.h" #include "logger.h" #include "memory.h" #include "parser.h" #include "smtp.h" #include "utils.h" #include "html.h" /* SSL primitives */ /* Free an SSL context */ void clear_ssl(ssl_data_t *ssl) { if (ssl) if (ssl->ctx) SSL_CTX_free(ssl->ctx); } /* PEM password callback function */ static int password_cb(char *buf, int num, int rwflag, void *userdata) { ssl_data_t *ssl = (ssl_data_t *) userdata; unsigned int plen = strlen(ssl->password); if (num < plen + 1) return (0); strncpy(buf, ssl->password, plen); return (plen); } /* Inititalize global SSL context */ static BIO *bio_err = 0; static int build_ssl_ctx(void) { ssl_data_t *ssl; /* Library initialization */ SSL_library_init(); SSL_load_error_strings(); bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); if (!check_data->ssl) ssl = (ssl_data_t *) MALLOC(sizeof(ssl_data_t)); else ssl = check_data->ssl; /* Initialize SSL context for SSL v2/3 */ ssl->meth = (SSL_METHOD *) SSLv23_method(); ssl->ctx = SSL_CTX_new(ssl->meth); /* return for autogen context */ if (!check_data->ssl) { check_data->ssl = ssl; goto end; } /* Load our keys and certificates */ if (check_data->ssl->certfile) if (! (SSL_CTX_use_certificate_chain_file (ssl->ctx, check_data->ssl->certfile))) { log_message(LOG_INFO, "SSL error : Cant load certificate file..."); return 0; } /* Handle password callback using userdata ssl */ if (check_data->ssl->password) { SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, check_data->ssl); SSL_CTX_set_default_passwd_cb(ssl->ctx, password_cb); } if (check_data->ssl->keyfile) if (! (SSL_CTX_use_PrivateKey_file (ssl->ctx, check_data->ssl->keyfile, SSL_FILETYPE_PEM))) { log_message(LOG_INFO, "SSL error : Cant load key file..."); return 0; } /* Load the CAs we trust */ if (check_data->ssl->cafile) if (! (SSL_CTX_load_verify_locations (ssl->ctx, check_data->ssl->cafile, 0))) { log_message(LOG_INFO, "SSL error : Cant load CA file..."); return 0; } end: #if (OPENSSL_VERSION_NUMBER < 0x00905100L) SSL_CTX_set_verify_depth(ssl->ctx, 1); #endif return 1; } /* * Initialize the SSL context, with or without specific * configuration files. */ int init_ssl_ctx(void) { ssl_data_t *ssl = check_data->ssl; if (!build_ssl_ctx()) { log_message(LOG_INFO, "Error Initialize SSL, ctx Instance"); log_message(LOG_INFO, " SSL keyfile:%s", ssl->keyfile); log_message(LOG_INFO, " SSL password:%s", ssl->password); log_message(LOG_INFO, " SSL cafile:%s", ssl->cafile); log_message(LOG_INFO, "Terminate..."); clear_ssl(ssl); return 0; } return 1; } /* Display SSL error to readable string */ int ssl_printerr(int err) { unsigned long extended_error = 0; char *ssl_strerr; switch (err) { case SSL_ERROR_ZERO_RETURN: log_message(LOG_INFO, " SSL error: (zero return)"); break; case SSL_ERROR_WANT_READ: log_message(LOG_INFO, " SSL error: (read error)"); break; case SSL_ERROR_WANT_WRITE: log_message(LOG_INFO, " SSL error: (write error)"); break; case SSL_ERROR_WANT_CONNECT: log_message(LOG_INFO, " SSL error: (connect error)"); break; case SSL_ERROR_WANT_X509_LOOKUP: log_message(LOG_INFO, " SSL error: (X509 lookup error)"); break; case SSL_ERROR_SYSCALL: log_message(LOG_INFO, " SSL error: (syscall error)"); break; case SSL_ERROR_SSL:{ ssl_strerr = (char *) MALLOC(500); extended_error = ERR_get_error(); ERR_error_string(extended_error, ssl_strerr); log_message(LOG_INFO, " SSL error: (%s)", ssl_strerr); FREE(ssl_strerr); break; } } return 0; } int ssl_connect(thread_t * thread, int new_req) { checker_t *checker = THREAD_ARG(thread); http_checker_t *http_get_check = CHECKER_ARG(checker); http_t *http = HTTP_ARG(http_get_check); request_t *req = HTTP_REQ(http); int ret = 0; int val = 0; /* First round, create SSL context */ if (new_req) { req->ssl = SSL_new(check_data->ssl->ctx); req->bio = BIO_new_socket(thread->u.fd, BIO_NOCLOSE); SSL_set_bio(req->ssl, req->bio, req->bio); } /* Set descriptor non blocking */ val = fcntl(thread->u.fd, F_GETFL, 0); fcntl(thread->u.fd, F_SETFL, val | O_NONBLOCK); ret = SSL_connect(req->ssl); /* restore descriptor flags */ fcntl(thread->u.fd, F_SETFL, val); return ret; } int ssl_send_request(SSL * ssl, char *str_request, int request_len) { int err, r = 0; while (1) { err = 1; r = SSL_write(ssl, str_request, request_len); if (SSL_ERROR_NONE != SSL_get_error(ssl, r)) break; err++; if (request_len != r) break; err++; break; } return (err == 3) ? 1 : 0; } /* Asynchronous SSL stream reader */ int ssl_read_thread(thread_t * thread) { checker_t *checker = THREAD_ARG(thread); http_checker_t *http_get_check = CHECKER_ARG(checker); http_t *http = HTTP_ARG(http_get_check); request_t *req = HTTP_REQ(http); unsigned timeout = checker->co->connection_to; unsigned char digest[16]; int r = 0; int val; /* Handle read timeout */ if (thread->type == THREAD_READ_TIMEOUT && !req->extracted) return timeout_epilog(thread, "=> SSL CHECK failed on service" " : recevice data <=\n\n", "SSL read"); /* Set descriptor non blocking */ val = fcntl(thread->u.fd, F_GETFL, 0); fcntl(thread->u.fd, F_SETFL, val | O_NONBLOCK); /* read the SSL stream */ r = SSL_read(req->ssl, req->buffer + req->len, MAX_BUFFER_LENGTH - req->len); /* restore descriptor flags */ fcntl(thread->u.fd, F_SETFL, val); req->error = SSL_get_error(req->ssl, r); if (req->error == SSL_ERROR_WANT_READ) { /* async read unfinished */ thread_add_read(thread->master, ssl_read_thread, checker, thread->u.fd, timeout); } else if (r > 0 && req->error == 0) { /* Handle response stream */ http_process_response(req, r); /* * Register next ssl stream reader. * Register itself to not perturbe global I/O multiplexer. */ thread_add_read(thread->master, ssl_read_thread, checker, thread->u.fd, timeout); } else if (req->error) { /* All the SSL streal has been parsed */ MD5_Final(digest, &req->context); SSL_set_quiet_shutdown(req->ssl, 1); r = (req->error == SSL_ERROR_ZERO_RETURN) ? SSL_shutdown(req->ssl) : 0; if (r && !req->extracted) { /* check if server is currently alive */ if (svr_checker_up(checker->id, checker->rs)) { smtp_alert(checker->rs, NULL, NULL, "DOWN", "=> SSL CHECK failed on service" " : cannot receive data <=\n\n"); update_svr_checker_state(DOWN, checker->id , checker->vs , checker->rs); } return epilog(thread, 1, 0, 0); } /* Handle response stream */ http_handle_response(thread, digest, (!req->extracted) ? 1 : 0); } return 0; } keepalived-1.2.13/keepalived/check/check_daemon.c0000644000175000017500000001537412334072037021470 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Healthcheckrs child process handling. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "check_daemon.h" #include "check_parser.h" #include "ipwrapper.h" #include "ipvswrapper.h" #include "check_data.h" #include "check_ssl.h" #include "check_api.h" #include "global_data.h" #include "ipwrapper.h" #include "ipvswrapper.h" #include "pidfile.h" #include "daemon.h" #include "signals.h" #include "logger.h" #include "list.h" #include "main.h" #include "memory.h" #include "parser.h" #include "vrrp_netlink.h" #include "vrrp_if.h" #ifdef _WITH_SNMP_ #include "check_snmp.h" #endif extern char *checkers_pidfile; /* Daemon stop sequence */ static void stop_check(void) { /* Destroy master thread */ signal_handler_destroy(); thread_destroy_master(master); free_checkers_queue(); free_ssl(); if (!(debug & 16)) clear_services(); ipvs_stop(); #ifdef _WITH_SNMP_ if (snmp) check_snmp_agent_close(); #endif /* Stop daemon */ pidfile_rm(checkers_pidfile); /* Clean data */ free_global_data(global_data); free_check_data(check_data); #ifdef _WITH_VRRP_ free_interface_queue(); #endif #ifdef _DEBUG_ keepalived_free_final("Healthcheck child process"); #endif /* * Reached when terminate signal catched. * finally return to parent process. */ closelog(); exit(0); } /* Daemon init sequence */ static void start_check(void) { /* Initialize sub-system */ if (ipvs_start() != IPVS_SUCCESS) { stop_check(); return; } init_checkers_queue(); #ifdef _WITH_VRRP_ init_interface_queue(); kernel_netlink_init(); #endif #ifdef _WITH_SNMP_ if (!reload && snmp) check_snmp_agent_init(); #endif /* Parse configuration file */ global_data = alloc_global_data(); check_data = alloc_check_data(); init_data(conf_file, check_init_keywords); if (!check_data) { stop_check(); return; } /* Post initializations */ log_message(LOG_INFO, "Configuration is using : %lu Bytes", mem_allocated); /* SSL load static data & initialize common ctx context */ if (!init_ssl_ctx()) { stop_check(); return; } /* Processing differential configuration parsing */ if (reload) { clear_diff_services(); copy_srv_states(); } /* Initialize IPVS topology */ if (!init_services()) { stop_check(); return; } /* Dump configuration */ if (debug & 4) { dump_global_data(global_data); dump_check_data(check_data); } #ifdef _WITH_VRRP_ /* Initialize linkbeat */ init_interface_linkbeat(); #endif /* Register checkers thread */ register_checkers_thread(); } /* Reload handler */ int reload_check_thread(thread_t *); void sighup_check(void *v, int sig) { thread_add_event(master, reload_check_thread, NULL, 0); } /* Terminate handler */ void sigend_check(void *v, int sig) { if (master) thread_add_terminate_event(master); } /* CHECK Child signal handling */ void check_signal_init(void) { signal_handler_init(); signal_set(SIGHUP, sighup_check, NULL); signal_set(SIGINT, sigend_check, NULL); signal_set(SIGTERM, sigend_check, NULL); signal_ignore(SIGPIPE); } /* Reload thread */ int reload_check_thread(thread_t * thread) { /* set the reloading flag */ SET_RELOAD; log_message(LOG_INFO, "Got SIGHUP, reloading checker configuration"); /* Signals handling */ signal_reset(); signal_handler_destroy(); /* Destroy master thread */ thread_destroy_master(master); master = thread_make_master(); free_global_data(global_data); free_checkers_queue(); #ifdef _WITH_VRRP_ free_interface_queue(); #endif free_ssl(); ipvs_stop(); /* Save previous conf data */ old_check_data = check_data; check_data = NULL; /* Reload the conf */ mem_allocated = 0; check_signal_init(); signal_set(SIGCHLD, thread_child_handler, master); start_check(); /* free backup data */ free_check_data(old_check_data); UNSET_RELOAD; return 0; } /* CHECK Child respawning thread */ int check_respawn_thread(thread_t * thread) { pid_t pid; /* Fetch thread args */ pid = THREAD_CHILD_PID(thread); /* Restart respawning thread */ if (thread->type == THREAD_CHILD_TIMEOUT) { thread_add_child(master, check_respawn_thread, NULL, pid, RESPAWN_TIMER); return 0; } /* We catch a SIGCHLD, handle it */ if (!(debug & 64)) { log_message(LOG_ALERT, "Healthcheck child process(%d) died: Respawning", pid); start_check_child(); } else { log_message(LOG_ALERT, "Healthcheck child process(%d) died: Exiting", pid); raise(SIGTERM); } return 0; } /* Register CHECK thread */ int start_check_child(void) { #ifndef _DEBUG_ pid_t pid; int ret; /* Initialize child process */ pid = fork(); if (pid < 0) { log_message(LOG_INFO, "Healthcheck child process: fork error(%s)" , strerror(errno)); return -1; } else if (pid) { checkers_child = pid; log_message(LOG_INFO, "Starting Healthcheck child process, pid=%d" , pid); /* Start respawning thread */ thread_add_child(master, check_respawn_thread, NULL, pid, RESPAWN_TIMER); return 0; } /* Opening local CHECK syslog channel */ openlog(PROG_CHECK, LOG_PID | ((debug & 1) ? LOG_CONS : 0), (log_facility==LOG_DAEMON) ? LOG_LOCAL2 : log_facility); /* Child process part, write pidfile */ if (!pidfile_write(checkers_pidfile, getpid())) { log_message(LOG_INFO, "Healthcheck child process: cannot write pidfile"); exit(0); } /* Create the new master thread */ signal_handler_destroy(); thread_destroy_master(master); master = thread_make_master(); /* change to / dir */ ret = chdir("/"); if (ret < 0) { log_message(LOG_INFO, "Healthcheck child process: error chdir"); } /* Set mask */ umask(0); #endif /* If last process died during a reload, we can get there and we * don't want to loop again, because we're not reloading anymore. */ UNSET_RELOAD; /* Signal handling initialization */ check_signal_init(); /* Start Healthcheck daemon */ start_check(); /* Launch the scheduling I/O multiplexer */ launch_scheduler(); /* Finish healthchecker daemon process */ stop_check(); exit(0); } keepalived-1.2.13/keepalived/check/check_data.c0000644000175000017500000002330612334072037021130 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Healthcheckers dynamic data structure definition. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include #include "check_data.h" #include "check_api.h" #include "logger.h" #include "memory.h" #include "utils.h" #include "ipwrapper.h" /* global vars */ check_data_t *check_data = NULL; check_data_t *old_check_data = NULL; /* SSL facility functions */ ssl_data_t * alloc_ssl(void) { ssl_data_t *ssl = (ssl_data_t *) MALLOC(sizeof(ssl_data_t)); return ssl; } void free_ssl(void) { ssl_data_t *ssl = check_data->ssl; if (!ssl) return; FREE_PTR(ssl->password); FREE_PTR(ssl->cafile); FREE_PTR(ssl->certfile); FREE_PTR(ssl->keyfile); FREE(ssl); } static void dump_ssl(void) { ssl_data_t *ssl = check_data->ssl; if (ssl->password) log_message(LOG_INFO, " Password : %s", ssl->password); if (ssl->cafile) log_message(LOG_INFO, " CA-file : %s", ssl->cafile); if (ssl->certfile) log_message(LOG_INFO, " Certificate file : %s", ssl->certfile); if (ssl->keyfile) log_message(LOG_INFO, " Key file : %s", ssl->keyfile); if (!ssl->password && !ssl->cafile && !ssl->certfile && !ssl->keyfile) log_message(LOG_INFO, " Using autogen SSL context"); } /* Virtual server group facility functions */ static void free_vsg(void *data) { virtual_server_group_t *vsg = data; FREE_PTR(vsg->gname); free_list(vsg->addr_ip); free_list(vsg->range); free_list(vsg->vfwmark); FREE(vsg); } static void dump_vsg(void *data) { virtual_server_group_t *vsg = data; log_message(LOG_INFO, " Virtual Server Group = %s", vsg->gname); dump_list(vsg->addr_ip); dump_list(vsg->range); dump_list(vsg->vfwmark); } static void free_vsg_entry(void *data) { FREE(data); } static void dump_vsg_entry(void *data) { virtual_server_group_entry_t *vsg_entry = data; if (vsg_entry->vfwmark) log_message(LOG_INFO, " FWMARK = %d", vsg_entry->vfwmark); else if (vsg_entry->range) log_message(LOG_INFO, " VIP Range = %s-%d, VPORT = %d" , inet_sockaddrtos(&vsg_entry->addr) , vsg_entry->range , ntohs(inet_sockaddrport(&vsg_entry->addr))); else log_message(LOG_INFO, " VIP = %s, VPORT = %d" , inet_sockaddrtos(&vsg_entry->addr) , ntohs(inet_sockaddrport(&vsg_entry->addr))); } void alloc_vsg(char *gname) { int size = strlen(gname); virtual_server_group_t *new; new = (virtual_server_group_t *) MALLOC(sizeof(virtual_server_group_t)); new->gname = (char *) MALLOC(size + 1); memcpy(new->gname, gname, size); new->addr_ip = alloc_list(free_vsg_entry, dump_vsg_entry); new->range = alloc_list(free_vsg_entry, dump_vsg_entry); new->vfwmark = alloc_list(free_vsg_entry, dump_vsg_entry); list_add(check_data->vs_group, new); } void alloc_vsg_entry(vector_t *strvec) { virtual_server_group_t *vsg = LIST_TAIL_DATA(check_data->vs_group); virtual_server_group_entry_t *new; new = (virtual_server_group_entry_t *) MALLOC(sizeof(virtual_server_group_entry_t)); if (!strcmp(vector_slot(strvec, 0), "fwmark")) { new->vfwmark = atoi(vector_slot(strvec, 1)); list_add(vsg->vfwmark, new); } else { new->range = inet_stor(vector_slot(strvec, 0)); inet_stosockaddr(vector_slot(strvec, 0), vector_slot(strvec, 1), &new->addr); if (!new->range) list_add(vsg->addr_ip, new); else list_add(vsg->range, new); } } /* Virtual server facility functions */ static void free_vs(void *data) { virtual_server_t *vs = data; FREE_PTR(vs->vsgname); FREE_PTR(vs->virtualhost); FREE_PTR(vs->s_svr); free_list(vs->rs); FREE_PTR(vs->quorum_up); FREE_PTR(vs->quorum_down); FREE(vs); } static void dump_vs(void *data) { virtual_server_t *vs = data; if (vs->vsgname) log_message(LOG_INFO, " VS GROUP = %s", vs->vsgname); else if (vs->vfwmark) log_message(LOG_INFO, " VS FWMARK = %d", vs->vfwmark); else log_message(LOG_INFO, " VIP = %s, VPORT = %d" , inet_sockaddrtos(&vs->addr), ntohs(inet_sockaddrport(&vs->addr))); if (vs->virtualhost) log_message(LOG_INFO, " VirtualHost = %s", vs->virtualhost); log_message(LOG_INFO, " delay_loop = %lu, lb_algo = %s", (vs->delay_loop >= TIMER_MAX_SEC) ? vs->delay_loop/TIMER_HZ : vs->delay_loop, vs->sched); if (atoi(vs->timeout_persistence) > 0) log_message(LOG_INFO, " persistence timeout = %s", vs->timeout_persistence); if (vs->granularity_persistence) log_message(LOG_INFO, " persistence granularity = %s", inet_ntop2(vs->granularity_persistence)); log_message(LOG_INFO, " protocol = %s", (vs->service_type == IPPROTO_TCP) ? "TCP" : "UDP"); log_message(LOG_INFO, " alpha is %s, omega is %s", vs->alpha ? "ON" : "OFF", vs->omega ? "ON" : "OFF"); log_message(LOG_INFO, " quorum = %lu, hysteresis = %lu", vs->quorum, vs->hysteresis); if (vs->quorum_up) log_message(LOG_INFO, " -> Notify script UP = %s", vs->quorum_up); if (vs->quorum_down) log_message(LOG_INFO, " -> Notify script DOWN = %s", vs->quorum_down); if (vs->ha_suspend) log_message(LOG_INFO, " Using HA suspend"); switch (vs->loadbalancing_kind) { #ifdef _WITH_LVS_ case IP_VS_CONN_F_MASQ: log_message(LOG_INFO, " lb_kind = NAT"); break; case IP_VS_CONN_F_DROUTE: log_message(LOG_INFO, " lb_kind = DR"); break; case IP_VS_CONN_F_TUNNEL: log_message(LOG_INFO, " lb_kind = TUN"); break; #endif } if (vs->s_svr) { log_message(LOG_INFO, " sorry server = %s" , FMT_RS(vs->s_svr)); } if (!LIST_ISEMPTY(vs->rs)) dump_list(vs->rs); } void alloc_vs(char *ip, char *port) { int size = strlen(port); virtual_server_t *new; new = (virtual_server_t *) MALLOC(sizeof(virtual_server_t)); if (!strcmp(ip, "group")) { new->vsgname = (char *) MALLOC(size + 1); memcpy(new->vsgname, port, size); } else if (!strcmp(ip, "fwmark")) { new->vfwmark = atoi(port); } else { inet_stosockaddr(ip, port, &new->addr); } new->delay_loop = KEEPALIVED_DEFAULT_DELAY; strncpy(new->timeout_persistence, "0", 1); new->virtualhost = NULL; new->alpha = 0; new->omega = 0; new->quorum_up = NULL; new->quorum_down = NULL; new->quorum = 1; new->hysteresis = 0; new->quorum_state = UP; list_add(check_data->vs, new); } /* Sorry server facility functions */ void alloc_ssvr(char *ip, char *port) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); vs->s_svr = (real_server_t *) MALLOC(sizeof(real_server_t)); vs->s_svr->weight = 1; vs->s_svr->iweight = 1; inet_stosockaddr(ip, port, &vs->s_svr->addr); } /* Real server facility functions */ static void free_rs(void *data) { real_server_t *rs = data; FREE_PTR(rs->notify_up); FREE_PTR(rs->notify_down); free_list(rs->failed_checkers); FREE(rs); } static void dump_rs(void *data) { real_server_t *rs = data; log_message(LOG_INFO, " RIP = %s, RPORT = %d, WEIGHT = %d" , inet_sockaddrtos(&rs->addr) , ntohs(inet_sockaddrport(&rs->addr)) , rs->weight); if (rs->inhibit) log_message(LOG_INFO, " -> Inhibit service on failure"); if (rs->notify_up) log_message(LOG_INFO, " -> Notify script UP = %s", rs->notify_up); if (rs->notify_down) log_message(LOG_INFO, " -> Notify script DOWN = %s", rs->notify_down); } static void free_failed_checkers(void *data) { FREE(data); } void alloc_rs(char *ip, char *port) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); real_server_t *new; new = (real_server_t *) MALLOC(sizeof(real_server_t)); inet_stosockaddr(ip, port, &new->addr); new->weight = 1; new->iweight = 1; new->failed_checkers = alloc_list(free_failed_checkers, NULL); if (LIST_ISEMPTY(vs->rs)) vs->rs = alloc_list(free_rs, dump_rs); list_add(vs->rs, new); } /* data facility functions */ check_data_t * alloc_check_data(void) { check_data_t *new; new = (check_data_t *) MALLOC(sizeof(check_data_t)); new->vs = alloc_list(free_vs, dump_vs); new->vs_group = alloc_list(free_vsg, dump_vsg); return new; } void free_check_data(check_data_t *data) { free_list(data->vs); free_list(data->vs_group); FREE(data); } void dump_check_data(check_data_t *data) { if (data->ssl) { log_message(LOG_INFO, "------< SSL definitions >------"); dump_ssl(); } if (!LIST_ISEMPTY(data->vs)) { log_message(LOG_INFO, "------< LVS Topology >------"); log_message(LOG_INFO, " System is compiled with LVS v%d.%d.%d", NVERSION(IP_VS_VERSION_CODE)); if (!LIST_ISEMPTY(data->vs_group)) dump_list(data->vs_group); dump_list(data->vs); } dump_checkers_queue(); } char * format_vs (virtual_server_t *vs) { static char addr_str[INET6_ADDRSTRLEN + 1]; /* alloc large buffer because of unknown length of vs->vsgname */ static char ret[512]; if (vs->vsgname) snprintf (ret, sizeof (ret) - 1, "[%s]:%d" , vs->vsgname , ntohs(inet_sockaddrport(&vs->addr))); else if (vs->vfwmark) snprintf (ret, sizeof (ret) - 1, "FWM %d", vs->vfwmark); else { inet_sockaddrtos2(&vs->addr, addr_str); snprintf(ret, sizeof(ret) - 1, "[%s]:%d" , addr_str , ntohs(inet_sockaddrport(&vs->addr))); } return ret; } keepalived-1.2.13/keepalived/check/check_tcp.c0000644000175000017500000000777212334072037021016 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: TCP checker. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "check_tcp.h" #include "check_api.h" #include "memory.h" #include "ipwrapper.h" #include "layer4.h" #include "logger.h" #include "smtp.h" #include "utils.h" #include "parser.h" int tcp_connect_thread(thread_t *); /* Configuration stream handling */ void free_tcp_check(void *data) { FREE(CHECKER_CO(data)); FREE(data); } void dump_tcp_check(void *data) { log_message(LOG_INFO, " Keepalive method = TCP_CHECK"); dump_conn_opts (CHECKER_GET_CO()); } void tcp_check_handler(vector_t *strvec) { /* queue new checker */ queue_checker(free_tcp_check, dump_tcp_check, tcp_connect_thread, NULL, CHECKER_NEW_CO()); } void install_tcp_check_keyword(void) { install_keyword("TCP_CHECK", &tcp_check_handler); install_sublevel(); install_connect_keywords(); install_keyword("warmup", &warmup_handler); install_sublevel_end(); } int tcp_check_thread(thread_t * thread) { checker_t *checker; int status; checker = THREAD_ARG(thread); status = tcp_socket_state(thread->u.fd, thread, tcp_check_thread); /* If status = connect_success, TCP connection to remote host is established. * Otherwise we have a real connection error or connection timeout. */ if (status == connect_success) { close(thread->u.fd); if (!svr_checker_up(checker->id, checker->rs)) { log_message(LOG_INFO, "TCP connection to %s success." , FMT_TCP_RS(checker)); smtp_alert(checker->rs, NULL, NULL, "UP", "=> TCP CHECK succeed on service <="); update_svr_checker_state(UP, checker->id , checker->vs , checker->rs); } } else { if (svr_checker_up(checker->id, checker->rs)) { log_message(LOG_INFO, "TCP connection to %s failed !!!" , FMT_TCP_RS(checker)); smtp_alert(checker->rs, NULL, NULL, "DOWN", "=> TCP CHECK failed on service <="); update_svr_checker_state(DOWN, checker->id , checker->vs , checker->rs); } } /* Register next timer checker */ if (status != connect_in_progress) thread_add_timer(thread->master, tcp_connect_thread, checker, checker->vs->delay_loop); return 0; } int tcp_connect_thread(thread_t * thread) { checker_t *checker = THREAD_ARG(thread); conn_opts_t *co = checker->co; int fd; int status; /* * Register a new checker thread & return * if checker is disabled */ if (!CHECKER_ENABLED(checker)) { thread_add_timer(thread->master, tcp_connect_thread, checker, checker->vs->delay_loop); return 0; } if ((fd = socket(co->dst.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { log_message(LOG_INFO, "TCP connect fail to create socket. Rescheduling."); thread_add_timer(thread->master, tcp_connect_thread, checker, checker->vs->delay_loop); return 0; } status = tcp_bind_connect(fd, co); /* handle tcp connection status & register check worker thread */ if(tcp_connection_state(fd, status, thread, tcp_check_thread, co->connection_to)) { close(fd); log_message(LOG_INFO, "TCP socket bind failed. Rescheduling."); thread_add_timer(thread->master, tcp_connect_thread, checker, checker->vs->delay_loop); } return 0; } keepalived-1.2.13/keepalived/check/check_parser.c0000644000175000017500000002250012334072037021506 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Configuration file parser/reader. Place into the dynamic * data structure representation the conf file representing * the loadbalanced server pool. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "check_parser.h" #include "check_data.h" #include "check_api.h" #include "global_data.h" #include "global_parser.h" #include "logger.h" #include "parser.h" #include "memory.h" #include "utils.h" #include "ipwrapper.h" /* SSL handlers */ static void ssl_handler(vector_t *strvec) { check_data->ssl = alloc_ssl(); } static void sslpass_handler(vector_t *strvec) { check_data->ssl->password = set_value(strvec); } static void sslca_handler(vector_t *strvec) { check_data->ssl->cafile = set_value(strvec); } static void sslcert_handler(vector_t *strvec) { check_data->ssl->certfile = set_value(strvec); } static void sslkey_handler(vector_t *strvec) { check_data->ssl->keyfile = set_value(strvec); } /* Virtual Servers handlers */ static void vsg_handler(vector_t *strvec) { /* Fetch queued vsg */ alloc_vsg(vector_slot(strvec, 1)); alloc_value_block(strvec, alloc_vsg_entry); } static void vs_handler(vector_t *strvec) { alloc_vs(vector_slot(strvec, 1), vector_slot(strvec, 2)); } static void delay_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); vs->delay_loop = atoi(vector_slot(strvec, 1)) * TIMER_HZ; if (vs->delay_loop < TIMER_HZ) vs->delay_loop = TIMER_HZ; } static void lbalgo_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); char *str = vector_slot(strvec, 1); int size = sizeof (vs->sched); int str_len = strlen(str); if (size > str_len) size = str_len; memcpy(vs->sched, str, size); } static void lbkind_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); char *str = vector_slot(strvec, 1); if (!strcmp(str, "NAT")) vs->loadbalancing_kind = IP_VS_CONN_F_MASQ; else if (!strcmp(str, "DR")) vs->loadbalancing_kind = IP_VS_CONN_F_DROUTE; else if (!strcmp(str, "TUN")) vs->loadbalancing_kind = IP_VS_CONN_F_TUNNEL; else log_message(LOG_INFO, "PARSER : unknown [%s] routing method.", str); } static void natmask_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); inet_ston(vector_slot(strvec, 1), &vs->nat_mask); } static void pto_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); char *str = vector_slot(strvec, 1); int size = sizeof (vs->timeout_persistence); int str_len = strlen(str); if (size > str_len) size = str_len; memcpy(vs->timeout_persistence, str, size); } static void pgr_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); if (vs->addr.ss_family == AF_INET6) vs->granularity_persistence = atoi(vector_slot(strvec, 1)); else inet_ston(vector_slot(strvec, 1), &vs->granularity_persistence); } static void proto_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); char *str = vector_slot(strvec, 1); vs->service_type = (!strcmp(str, "TCP")) ? IPPROTO_TCP : IPPROTO_UDP; } static void hasuspend_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); vs->ha_suspend = 1; } static void ops_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); vs->ops = 1; } static void virtualhost_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); vs->virtualhost = set_value(strvec); } /* Sorry Servers handlers */ static void ssvr_handler(vector_t *strvec) { alloc_ssvr(vector_slot(strvec, 1), vector_slot(strvec, 2)); } static void ssvri_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); if (vs->s_svr) { vs->s_svr->inhibit = 1; } else { log_message(LOG_ERR, "Ignoring sorry_server_inhibit used before or without sorry_server"); } } /* Real Servers handlers */ static void rs_handler(vector_t *strvec) { alloc_rs(vector_slot(strvec, 1), vector_slot(strvec, 2)); } static void weight_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); real_server_t *rs = LIST_TAIL_DATA(vs->rs); rs->weight = atoi(vector_slot(strvec, 1)); rs->iweight = rs->weight; } #ifdef _KRNL_2_6_ static void uthreshold_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); real_server_t *rs = LIST_TAIL_DATA(vs->rs); rs->u_threshold = atoi(vector_slot(strvec, 1)); } static void lthreshold_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); real_server_t *rs = LIST_TAIL_DATA(vs->rs); rs->l_threshold = atoi(vector_slot(strvec, 1)); } #endif static void inhibit_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); real_server_t *rs = LIST_TAIL_DATA(vs->rs); rs->inhibit = 1; } static void notify_up_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); real_server_t *rs = LIST_TAIL_DATA(vs->rs); rs->notify_up = set_value(strvec); } static void notify_down_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); real_server_t *rs = LIST_TAIL_DATA(vs->rs); rs->notify_down = set_value(strvec); } static void alpha_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); vs->alpha = 1; vs->quorum_state = DOWN; } static void omega_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); vs->omega = 1; } static void quorum_up_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); vs->quorum_up = set_value(strvec); } static void quorum_down_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); vs->quorum_down = set_value(strvec); } static void quorum_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); long tmp = atol (vector_slot(strvec, 1)); if (tmp < 1) { log_message(LOG_ERR, "Condition not met: Quorum >= 1"); log_message(LOG_ERR, "Ignoring requested value %s, using 1 instead", (char *) vector_slot(strvec, 1)); tmp = 1; } vs->quorum = tmp; } static void hysteresis_handler(vector_t *strvec) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); long tmp = atol (vector_slot(strvec, 1)); if (tmp < 0) { log_message(LOG_ERR, "Condition not met: 0 <= Hysteresis"); log_message(LOG_ERR, "Ignoring requested value %s, using 0 instead", (char *) vector_slot(strvec, 1)); tmp = 0; } vs->hysteresis = tmp; } vector_t * check_init_keywords(void) { /* global definitions mapping */ global_init_keywords(); /* SSL mapping */ install_keyword_root("SSL", &ssl_handler); install_keyword("password", &sslpass_handler); install_keyword("ca", &sslca_handler); install_keyword("certificate", &sslcert_handler); install_keyword("key", &sslkey_handler); /* Virtual server mapping */ install_keyword_root("virtual_server_group", &vsg_handler); install_keyword_root("virtual_server", &vs_handler); install_keyword("delay_loop", &delay_handler); install_keyword("lb_algo", &lbalgo_handler); install_keyword("lvs_sched", &lbalgo_handler); install_keyword("lb_kind", &lbkind_handler); install_keyword("lvs_method", &lbkind_handler); install_keyword("nat_mask", &natmask_handler); install_keyword("persistence_timeout", &pto_handler); install_keyword("persistence_granularity", &pgr_handler); install_keyword("protocol", &proto_handler); install_keyword("ha_suspend", &hasuspend_handler); install_keyword("ops", &ops_handler); install_keyword("virtualhost", &virtualhost_handler); /* Pool regression detection and handling. */ install_keyword("alpha", &alpha_handler); install_keyword("omega", &omega_handler); install_keyword("quorum_up", &quorum_up_handler); install_keyword("quorum_down", &quorum_down_handler); install_keyword("quorum", &quorum_handler); install_keyword("hysteresis", &hysteresis_handler); /* Real server mapping */ install_keyword("sorry_server", &ssvr_handler); install_keyword("sorry_server_inhibit", &ssvri_handler); install_keyword("real_server", &rs_handler); install_sublevel(); install_keyword("weight", &weight_handler); #ifdef _KRNL_2_6_ install_keyword("uthreshold", &uthreshold_handler); install_keyword("lthreshold", <hreshold_handler); #endif install_keyword("inhibit_on_failure", &inhibit_handler); install_keyword("notify_up", ¬ify_up_handler); install_keyword("notify_down", ¬ify_down_handler); /* Checkers mapping */ install_checkers_keyword(); install_sublevel_end(); return keywords; } keepalived-1.2.13/keepalived/check/ipwrapper.c0000644000175000017500000004470412334072037021100 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Manipulation functions for IPVS & IPFW wrappers. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "ipwrapper.h" #include "ipvswrapper.h" #include "logger.h" #include "memory.h" #include "utils.h" #include "notify.h" #include "main.h" #ifdef _WITH_SNMP_ #include "check_snmp.h" #endif /* out-of-order functions declarations */ static void update_quorum_state(virtual_server_t * vs); /* Returns the sum of all RS weight in a virtual server. */ long unsigned weigh_live_realservers(virtual_server_t * vs) { element e; real_server_t *svr; long unsigned count = 0; for (e = LIST_HEAD(vs->rs); e; ELEMENT_NEXT(e)) { svr = ELEMENT_DATA(e); if (ISALIVE(svr)) count += svr->weight; } return count; } /* Remove a realserver IPVS rule */ static int clear_service_rs(list vs_group, virtual_server_t * vs, list l) { element e; real_server_t *rs; long unsigned weight_sum; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { rs = ELEMENT_DATA(e); if (ISALIVE(rs)) { log_message(LOG_INFO, "Removing service %s from VS %s" , FMT_RS(rs) , FMT_VS(vs)); if (!ipvs_cmd(LVS_CMD_DEL_DEST, vs_group, vs, rs)) return 0; UNSET_ALIVE(rs); if (!vs->omega) continue; /* In Omega mode we call VS and RS down notifiers * all the way down the exit, as necessary. */ if (rs->notify_down) { log_message(LOG_INFO, "Executing [%s] for service %s in VS %s" , rs->notify_down , FMT_RS(rs) , FMT_VS(vs)); notify_exec(rs->notify_down); } #ifdef _WITH_SNMP_ check_snmp_rs_trap(rs, vs); #endif /* Sooner or later VS will lose the quorum (if any). However, * we don't push in a sorry server then, hence the regression * is intended. */ weight_sum = weigh_live_realservers(vs); if (vs->quorum_state == UP && ( !weight_sum || weight_sum < vs->quorum - vs->hysteresis) ) { vs->quorum_state = DOWN; if (vs->quorum_down) { log_message(LOG_INFO, "Executing [%s] for VS %s" , vs->quorum_down , FMT_VS(vs)); notify_exec(vs->quorum_down); } #ifdef _WITH_SNMP_ check_snmp_quorum_trap(vs); #endif } } } return 1; } /* Remove a virtualserver IPVS rule */ static int clear_service_vs(list vs_group, virtual_server_t * vs) { /* Processing real server queue */ if (!LIST_ISEMPTY(vs->rs)) { if (vs->s_svr) { if (ISALIVE(vs->s_svr)) if (!ipvs_cmd(LVS_CMD_DEL_DEST, vs_group, vs, vs->s_svr)) return 0; } else if (!clear_service_rs(vs_group, vs, vs->rs)) return 0; /* The above will handle Omega case for VS as well. */ } if (!ipvs_cmd(LVS_CMD_DEL, vs_group, vs, NULL)) return 0; UNSET_ALIVE(vs); return 1; } /* IPVS cleaner processing */ int clear_services(void) { element e; list l = check_data->vs; virtual_server_t *vs; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vs = ELEMENT_DATA(e); if (!clear_service_vs(check_data->vs_group, vs)) return 0; } return 1; } /* Set a realserver IPVS rules */ static int init_service_rs(virtual_server_t * vs) { element e; real_server_t *rs; for (e = LIST_HEAD(vs->rs); e; ELEMENT_NEXT(e)) { rs = ELEMENT_DATA(e); /* In alpha mode, be pessimistic (or realistic?) and don't * add real servers into the VS pool. They will get there * later upon healthchecks recovery (if ever). */ if (vs->alpha) { if (! rs->reloaded) UNSET_ALIVE(rs); continue; } if (!ISALIVE(rs)) { if (!ipvs_cmd(LVS_CMD_ADD_DEST, check_data->vs_group, vs, rs)) return 0; else SET_ALIVE(rs); } else if (vs->vsgname) { UNSET_ALIVE(rs); if (!ipvs_cmd(LVS_CMD_ADD_DEST, check_data->vs_group, vs, rs)) return 0; SET_ALIVE(rs); } } return 1; } /* Set a virtualserver IPVS rules */ static int init_service_vs(virtual_server_t * vs) { /* Init the VS root */ if (!ISALIVE(vs) || vs->vsgname) { if (!ipvs_cmd(LVS_CMD_ADD, check_data->vs_group, vs, NULL)) return 0; else SET_ALIVE(vs); } /* Processing real server queue */ if (!LIST_ISEMPTY(vs->rs)) { if (vs->alpha && ! vs->reloaded) vs->quorum_state = DOWN; if (!init_service_rs(vs)) return 0; } /* if the service was reloaded, we may have got/lost quorum due to quorum setting changed */ if (vs->reloaded) update_quorum_state(vs); return 1; } /* Set IPVS rules */ int init_services(void) { element e; list l = check_data->vs; virtual_server_t *vs; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vs = ELEMENT_DATA(e); if (!init_service_vs(vs)) return 0; } return 1; } /* add or remove _alive_ real servers from a virtual server */ void perform_quorum_state(virtual_server_t *vs, int add) { element e; real_server_t *rs; if (LIST_ISEMPTY(vs->rs)) return; log_message(LOG_INFO, "%s the pool for VS %s" , add?"Adding alive servers to":"Removing alive servers from" , FMT_VS(vs)); for (e = LIST_HEAD(vs->rs); e; ELEMENT_NEXT(e)) { rs = ELEMENT_DATA(e); if (!ISALIVE(rs)) /* We only handle alive servers */ continue; if (add) rs->alive = 0; ipvs_cmd(add?LVS_CMD_ADD_DEST:LVS_CMD_DEL_DEST, check_data->vs_group, vs, rs); rs->alive = 1; } } /* set quorum state depending on current weight of real servers */ static void update_quorum_state(virtual_server_t * vs) { long unsigned weight_sum = weigh_live_realservers(vs); /* If we have just gained quorum, it's time to consider notify_up. */ if (vs->quorum_state == DOWN && weight_sum >= vs->quorum + vs->hysteresis) { vs->quorum_state = UP; log_message(LOG_INFO, "Gained quorum %lu+%lu=%lu <= %u for VS %s" , vs->quorum , vs->hysteresis , vs->quorum + vs->hysteresis , weight_sum , FMT_VS(vs)); if (vs->s_svr && ISALIVE(vs->s_svr)) { log_message(LOG_INFO, "%s sorry server %s from VS %s" , (vs->s_svr->inhibit ? "Disabling" : "Removing") , FMT_RS(vs->s_svr) , FMT_VS(vs)); ipvs_cmd(LVS_CMD_DEL_DEST, check_data->vs_group, vs, vs->s_svr); vs->s_svr->alive = 0; /* Adding back alive real servers */ perform_quorum_state(vs, 1); } if (vs->quorum_up) { log_message(LOG_INFO, "Executing [%s] for VS %s" , vs->quorum_up , FMT_VS(vs)); notify_exec(vs->quorum_up); } #ifdef _WITH_SNMP_ check_snmp_quorum_trap(vs); #endif return; } /* If we have just lost quorum for the VS, we need to consider * VS notify_down and sorry_server cases */ if (vs->quorum_state == UP && ( !weight_sum || weight_sum < vs->quorum - vs->hysteresis) ) { vs->quorum_state = DOWN; log_message(LOG_INFO, "Lost quorum %lu-%lu=%lu > %u for VS %s" , vs->quorum , vs->hysteresis , vs->quorum - vs->hysteresis , weight_sum , FMT_VS(vs)); if (vs->quorum_down) { log_message(LOG_INFO, "Executing [%s] for VS %s" , vs->quorum_down , FMT_VS(vs)); notify_exec(vs->quorum_down); } if (vs->s_svr) { log_message(LOG_INFO, "%s sorry server %s to VS %s" , (vs->s_svr->inhibit ? "Enabling" : "Adding") , FMT_RS(vs->s_svr) , FMT_VS(vs)); /* the sorry server is now up in the pool, we flag it alive */ ipvs_cmd(LVS_CMD_ADD_DEST, check_data->vs_group, vs, vs->s_svr); vs->s_svr->alive = 1; /* Remove remaining alive real servers */ perform_quorum_state(vs, 0); } #ifdef _WITH_SNMP_ check_snmp_quorum_trap(vs); #endif return; } } /* manipulate add/remove rs according to alive state */ void perform_svr_state(int alive, virtual_server_t * vs, real_server_t * rs) { /* * | ISALIVE(rs) | alive | context * | 0 | 0 | first check failed under alpha mode, unreachable here * | 0 | 1 | RS went up, add it to the pool * | 1 | 0 | RS went down, remove it from the pool * | 1 | 1 | first check succeeded w/o alpha mode, unreachable here */ if (!ISALIVE(rs) && alive) { log_message(LOG_INFO, "%s service %s to VS %s" , (rs->inhibit) ? "Enabling" : "Adding" , FMT_RS(rs) , FMT_VS(vs)); /* Add only if we have quorum or no sorry server */ if (vs->quorum_state == UP || !vs->s_svr || !ISALIVE(vs->s_svr)) { ipvs_cmd(LVS_CMD_ADD_DEST, check_data->vs_group, vs, rs); } rs->alive = alive; if (rs->notify_up) { log_message(LOG_INFO, "Executing [%s] for service %s in VS %s" , rs->notify_up , FMT_RS(rs) , FMT_VS(vs)); notify_exec(rs->notify_up); } #ifdef _WITH_SNMP_ check_snmp_rs_trap(rs, vs); #endif /* We may have gained quorum */ update_quorum_state(vs); } if (ISALIVE(rs) && !alive) { log_message(LOG_INFO, "%s service %s from VS %s" , (rs->inhibit) ? "Disabling" : "Removing" , FMT_RS(rs) , FMT_VS(vs)); /* server is down, it is removed from the LVS realserver pool * Remove only if we have quorum or no sorry server */ if (vs->quorum_state == UP || !vs->s_svr || !ISALIVE(vs->s_svr)) { ipvs_cmd(LVS_CMD_DEL_DEST, check_data->vs_group, vs, rs); } rs->alive = alive; if (rs->notify_down) { log_message(LOG_INFO, "Executing [%s] for service %s in VS %s" , rs->notify_down , FMT_RS(rs) , FMT_VS(vs)); notify_exec(rs->notify_down); } #ifdef _WITH_SNMP_ check_snmp_rs_trap(rs, vs); #endif /* We may have lost quorum */ update_quorum_state(vs); } } /* Store new weight in real_server struct and then update kernel. */ void update_svr_wgt(int weight, virtual_server_t * vs, real_server_t * rs) { if (weight != rs->weight) { log_message(LOG_INFO, "Changing weight from %d to %d for %s service %s of VS %s" , rs->weight , weight , ISALIVE(rs) ? "active" : "inactive" , FMT_RS(rs) , FMT_VS(vs)); rs->weight = weight; /* * Have weight change take effect now only if rs is in * the pool and alive and the quorum is met (or if * there is no sorry server). If not, it will take * effect later when it becomes alive. */ if (rs->set && ISALIVE(rs) && (vs->quorum_state == UP || !vs->s_svr || !ISALIVE(vs->s_svr))) ipvs_cmd(LVS_CMD_EDIT_DEST, check_data->vs_group, vs, rs); update_quorum_state(vs); } } /* Test if realserver is marked UP for a specific checker */ int svr_checker_up(checker_id_t cid, real_server_t *rs) { element e; list l = rs->failed_checkers; checker_id_t *id; /* * We assume there is not too much checker per * real server, so we consider this lookup as * o(1). */ for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { id = ELEMENT_DATA(e); if (*id == cid) return 0; } return 1; } /* Update checker's state */ void update_svr_checker_state(int alive, checker_id_t cid, virtual_server_t *vs, real_server_t *rs) { element e; list l = rs->failed_checkers; checker_id_t *id; /* Handle alive state. Depopulate failed_checkers and call * perform_svr_state() independently, letting the latter sort * things out itself. */ if (alive) { /* Remove the succeeded check from failed_checkers list. */ for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { id = ELEMENT_DATA(e); if (*id == cid) { free_list_element(l, e); /* If we don't break, the next iteration will trigger * a SIGSEGV. */ break; } } if (LIST_SIZE(l) == 0) perform_svr_state(alive, vs, rs); } /* Handle not alive state */ else { id = (checker_id_t *) MALLOC(sizeof(checker_id_t)); *id = cid; list_add(l, id); if (LIST_SIZE(l) == 1) perform_svr_state(alive, vs, rs); } } /* Check if a vsg entry is in new data */ static int vsge_exist(virtual_server_group_entry_t *vsg_entry, list l) { element e; virtual_server_group_entry_t *vsge; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsge = ELEMENT_DATA(e); if (VSGE_ISEQ(vsg_entry, vsge)) { /* * If vsge exist this entry * is alive since only rs entries * are changing from alive state. */ SET_ALIVE(vsge); return 1; } } return 0; } /* Clear the diff vsge of old group */ static int clear_diff_vsge(list old, list new, virtual_server_t * old_vs) { virtual_server_group_entry_t *vsge; element e; for (e = LIST_HEAD(old); e; ELEMENT_NEXT(e)) { vsge = ELEMENT_DATA(e); if (!vsge_exist(vsge, new)) { log_message(LOG_INFO, "VS [[%s]:%d:%d:%d] in group %s no longer exist" , inet_sockaddrtos(&vsge->addr) , ntohs(inet_sockaddrport(&vsge->addr)) , vsge->range , vsge->vfwmark , old_vs->vsgname); if (!ipvs_group_remove_entry(old_vs, vsge)) return 0; } } return 1; } /* Clear the diff vsg of the old vs */ static int clear_diff_vsg(virtual_server_t * old_vs) { virtual_server_group_t *old; virtual_server_group_t *new; /* Fetch group */ old = ipvs_get_group_by_name(old_vs->vsgname, old_check_data->vs_group); new = ipvs_get_group_by_name(old_vs->vsgname, check_data->vs_group); /* Diff the group entries */ if (!clear_diff_vsge(old->addr_ip, new->addr_ip, old_vs)) return 0; if (!clear_diff_vsge(old->range, new->range, old_vs)) return 0; if (!clear_diff_vsge(old->vfwmark, new->vfwmark, old_vs)) return 0; return 1; } /* Check if a vs exist in new data and returns pointer to it */ static virtual_server_t* vs_exist(virtual_server_t * old_vs) { element e; list l = check_data->vs; virtual_server_t *vs; virtual_server_group_t *vsg; if (LIST_ISEMPTY(l)) return NULL; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vs = ELEMENT_DATA(e); if (VS_ISEQ(old_vs, vs)) { /* Check if group exist */ if (vs->vsgname) { vsg = ipvs_get_group_by_name(old_vs->vsgname, check_data->vs_group); if (!vsg) return NULL; else if (!clear_diff_vsg(old_vs)) return NULL; } /* * Exist so set alive. */ SET_ALIVE(vs); return vs; } } return NULL; } /* Check if rs is in new vs data */ static int rs_exist(real_server_t * old_rs, list l) { element e; real_server_t *rs; if (LIST_ISEMPTY(l)) return 0; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { rs = ELEMENT_DATA(e); if (RS_ISEQ(rs, old_rs)) { /* * We reflect the previous alive * flag value to not try to set * already set IPVS rule. */ rs->alive = old_rs->alive; rs->set = old_rs->set; rs->weight = old_rs->weight; return 1; } } return 0; } /* get rs list for a specific vs */ static list get_rs_list(virtual_server_t * vs) { element e; list l = check_data->vs; virtual_server_t *vsvr; if (LIST_ISEMPTY(l)) return NULL; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsvr = ELEMENT_DATA(e); if (VS_ISEQ(vs, vsvr)) return vsvr->rs; } /* most of the time never reached */ return NULL; } /* Clear the diff rs of the old vs */ static int clear_diff_rs(list old_vs_group, virtual_server_t * old_vs) { element e; list l = old_vs->rs; list new = get_rs_list(old_vs); real_server_t *rs; /* If old vs didn't own rs then nothing return */ if (LIST_ISEMPTY(l)) return 1; /* remove RS from old vs which are not found in new vs */ list rs_to_remove = alloc_list (NULL, NULL); for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { rs = ELEMENT_DATA(e); if (!rs_exist(rs, new)) { /* Reset inhibit flag to delete inhibit entries */ log_message(LOG_INFO, "service %s no longer exist" , FMT_RS(rs)); rs->inhibit = 0; list_add (rs_to_remove, rs); } } int ret = clear_service_rs (old_vs_group, old_vs, rs_to_remove); free_list (rs_to_remove); return ret; } /* When reloading configuration, remove negative diff entries */ int clear_diff_services(void) { element e; list l = old_check_data->vs; virtual_server_t *vs; /* If old config didn't own vs then nothing return */ if (LIST_ISEMPTY(l)) return 1; /* Remove diff entries from previous IPVS rules */ for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vs = ELEMENT_DATA(e); /* * Try to find this vs into the new conf data * reloaded. */ if (!vs_exist(vs)) { if (vs->vsgname) log_message(LOG_INFO, "Removing Virtual Server Group [%s]" , vs->vsgname); else log_message(LOG_INFO, "Removing Virtual Server %s" , FMT_VS(vs)); /* Clear VS entry */ if (!clear_service_vs(old_check_data->vs_group, vs)) return 0; } else { /* If vs exist, perform rs pool diff */ /* omega = 0 must not prevent the notifiers from being called, because the VS still exists in new configuration */ vs->omega = 1; if (!clear_diff_rs(old_check_data->vs_group, vs)) return 0; if (vs->s_svr) if (ISALIVE(vs->s_svr)) if (!ipvs_cmd(LVS_CMD_DEL_DEST , check_data->vs_group , vs , vs->s_svr)) return 0; } } return 1; } /* When reloading configuration, copy still alive RS/VS alive/set attributes into corresponding new config items */ int copy_srv_states (void) { element e; list l = old_check_data->vs; virtual_server_t *old_vs, *new_vs; /* If old config didn't own vs then nothing return */ if (LIST_ISEMPTY(l)) return 1; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { old_vs = ELEMENT_DATA(e); new_vs = vs_exist (old_vs); if (new_vs) { /* copy quorum_state field of VS */ new_vs->quorum_state = old_vs->quorum_state; new_vs->reloaded = 1; list old_rsl = old_vs->rs; list new_rsl = new_vs->rs; if (LIST_ISEMPTY(old_rsl) || LIST_ISEMPTY (new_rsl)) continue; element oe, ne; real_server_t *old_rs, *new_rs; /* iterate over equal rs */ for (oe = LIST_HEAD(old_rsl); oe; ELEMENT_NEXT (oe)) { old_rs = ELEMENT_DATA(oe); for (ne = LIST_HEAD(new_rsl); ne; ELEMENT_NEXT(ne)) { new_rs = ELEMENT_DATA(ne); if (RS_ISEQ (old_rs, new_rs)) { /* copy alive, set fields of RS */ new_rs->alive = old_rs->alive; new_rs->set = old_rs->set; new_rs->reloaded = 1; if (new_rs->alive) { /* clear failed_checkers list */ free_list_elements(new_rs->failed_checkers); } break; } } } } } return 0; } keepalived-1.2.13/keepalived/check/check_misc.c0000644000175000017500000001634212334072037021154 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: MISC CHECK. Perform a system call to run an extra * system prog or script. * * Authors: Alexandre Cassen, * Eric Jarman, * Bradley Baetz, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "check_misc.h" #include "check_api.h" #include "memory.h" #include "ipwrapper.h" #include "logger.h" #include "smtp.h" #include "utils.h" #include "parser.h" #include "notify.h" #include "daemon.h" #include "signals.h" int misc_check_thread(thread_t *); int misc_check_child_thread(thread_t *); int misc_check_child_timeout_thread(thread_t *); /* Configuration stream handling */ void free_misc_check(void *data) { misc_checker_t *misck_checker = CHECKER_DATA(data); FREE(misck_checker->path); FREE(misck_checker); FREE(data); } void dump_misc_check(void *data) { misc_checker_t *misck_checker = CHECKER_DATA(data); log_message(LOG_INFO, " Keepalive method = MISC_CHECK"); log_message(LOG_INFO, " script = %s", misck_checker->path); log_message(LOG_INFO, " timeout = %lu", misck_checker->timeout/TIMER_HZ); log_message(LOG_INFO, " dynamic = %s", misck_checker->dynamic ? "YES" : "NO"); } void misc_check_handler(vector_t *strvec) { misc_checker_t *misck_checker = (misc_checker_t *) MALLOC(sizeof (misc_checker_t)); /* queue new checker */ queue_checker(free_misc_check, dump_misc_check, misc_check_thread, misck_checker, NULL); } void misc_path_handler(vector_t *strvec) { misc_checker_t *misck_checker = CHECKER_GET(); misck_checker->path = CHECKER_VALUE_STRING(strvec); } void misc_timeout_handler(vector_t *strvec) { misc_checker_t *misck_checker = CHECKER_GET(); misck_checker->timeout = CHECKER_VALUE_INT(strvec) * TIMER_HZ; } void misc_dynamic_handler(vector_t *strvec) { misc_checker_t *misck_checker = CHECKER_GET(); misck_checker->dynamic = 1; } void install_misc_check_keyword(void) { install_keyword("MISC_CHECK", &misc_check_handler); install_sublevel(); install_keyword("misc_path", &misc_path_handler); install_keyword("misc_timeout", &misc_timeout_handler); install_keyword("misc_dynamic", &misc_dynamic_handler); install_keyword("warmup", &warmup_handler); install_sublevel_end(); } int misc_check_thread(thread_t * thread) { checker_t *checker; misc_checker_t *misck_checker; int status, ret; pid_t pid; checker = THREAD_ARG(thread); misck_checker = CHECKER_ARG(checker); /* * Register a new checker thread & return * if checker is disabled */ if (!CHECKER_ENABLED(checker)) { /* Register next timer checker */ thread_add_timer(thread->master, misc_check_thread, checker, checker->vs->delay_loop); return 0; } /* Register next timer checker */ thread_add_timer(thread->master, misc_check_thread, checker, checker->vs->delay_loop); /* Daemonization to not degrade our scheduling timer */ pid = fork(); /* In case of fork is error. */ if (pid < 0) { log_message(LOG_INFO, "Failed fork process"); return -1; } /* In case of this is parent process */ if (pid) { long timeout; timeout = (misck_checker->timeout) ? misck_checker->timeout : checker->vs->delay_loop; thread_add_child(thread->master, misc_check_child_thread, checker, pid, timeout); return 0; } /* Child part */ signal_handler_destroy(); closeall(0); open("/dev/null", O_RDWR); ret = dup(0); if (ret < 0) { log_message(LOG_INFO, "dup(0) error"); } ret = dup(0); if (ret < 0) { log_message(LOG_INFO, "dup(0) error"); } status = system_call(misck_checker->path); if (status < 0 || !WIFEXITED(status)) status = 0; /* Script errors aren't server errors */ else status = WEXITSTATUS(status); exit(status); } int misc_check_child_thread(thread_t * thread) { int wait_status; checker_t *checker; misc_checker_t *misck_checker; checker = THREAD_ARG(thread); misck_checker = CHECKER_ARG(checker); if (thread->type == THREAD_CHILD_TIMEOUT) { pid_t pid; pid = THREAD_CHILD_PID(thread); /* The child hasn't responded. Kill it off. */ if (svr_checker_up(checker->id, checker->rs)) { log_message(LOG_INFO, "Misc check to [%s] for [%s] timed out" , inet_sockaddrtos(&checker->rs->addr) , misck_checker->path); smtp_alert(checker->rs, NULL, NULL, "DOWN", "=> MISC CHECK script timeout on service <="); update_svr_checker_state(DOWN, checker->id , checker->vs , checker->rs); } kill(pid, SIGTERM); thread_add_child(thread->master, misc_check_child_timeout_thread, checker, pid, 2); return 0; } wait_status = THREAD_CHILD_STATUS(thread); if (WIFEXITED(wait_status)) { int status; status = WEXITSTATUS(wait_status); if (status == 0 || (misck_checker->dynamic == 1 && status >= 2 && status <= 255)) { /* * The actual weight set when using misc_dynamic is two less than * the exit status returned. Effective range is 0..253. * Catch legacy case of status being 0 but misc_dynamic being set. */ if (misck_checker->dynamic == 1 && status != 0) update_svr_wgt(status - 2, checker->vs, checker->rs); /* everything is good */ if (!svr_checker_up(checker->id, checker->rs)) { log_message(LOG_INFO, "Misc check to [%s] for [%s] success." , inet_sockaddrtos(&checker->rs->addr) , misck_checker->path); smtp_alert(checker->rs, NULL, NULL, "UP", "=> MISC CHECK succeed on service <="); update_svr_checker_state(UP, checker->id , checker->vs , checker->rs); } } else { if (svr_checker_up(checker->id, checker->rs)) { log_message(LOG_INFO, "Misc check to [%s] for [%s] failed." , inet_sockaddrtos(&checker->rs->addr) , misck_checker->path); smtp_alert(checker->rs, NULL, NULL, "DOWN", "=> MISC CHECK failed on service <="); update_svr_checker_state(DOWN, checker->id , checker->vs , checker->rs); } } } return 0; } int misc_check_child_timeout_thread(thread_t * thread) { pid_t pid; if (thread->type != THREAD_CHILD_TIMEOUT) return 0; /* OK, it still hasn't exited. Now really kill it off. */ pid = THREAD_CHILD_PID(thread); if (kill(pid, SIGKILL) < 0) { /* Its possible it finished while we're handing this */ if (errno != ESRCH) DBG("kill error: %s", strerror(errno)); return 0; } log_message(LOG_WARNING, "Process [%d] didn't respond to SIGTERM", pid); waitpid(pid, NULL, 0); return 0; } keepalived-1.2.13/keepalived/check/check_api.c0000644000175000017500000001753412334072037020776 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Checkers registration. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include #include #include "check_api.h" #include "main.h" #include "parser.h" #include "memory.h" #include "utils.h" #include "logger.h" #include "global_data.h" #include "check_misc.h" #include "check_smtp.h" #include "check_tcp.h" #include "check_http.h" #include "check_ssl.h" /* Global vars */ static checker_id_t ncheckers = 0; list checkers_queue; /* free checker data */ static void free_checker(void *data) { checker_t *checker= data; (*checker->free_func) (checker); } /* dump checker data */ static void dump_checker(void *data) { checker_t *checker = data; log_message(LOG_INFO, " %s", FMT_CHK(checker)); (*checker->dump_func) (checker); } void dump_conn_opts (conn_opts_t *conn) { log_message(LOG_INFO, " Connection dest = %s", inet_sockaddrtopair(&conn->dst)); if (conn->bindto.ss_family) log_message(LOG_INFO, " Bind to = %s", inet_sockaddrtopair(&conn->bindto)); log_message(LOG_INFO, " Connection timeout = %d", conn->connection_to/TIMER_HZ); } /* Queue a checker into the checkers_queue */ void queue_checker(void (*free_func) (void *), void (*dump_func) (void *) , int (*launch) (thread_t *) , void *data , conn_opts_t *co) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); real_server_t *rs = LIST_TAIL_DATA(vs->rs); checker_t *checker = (checker_t *) MALLOC(sizeof (checker_t)); /* Set default dst = RS, timeout = 5 */ if (co) { co->dst = rs->addr; co->connection_to = 5 * TIMER_HZ; } checker->free_func = free_func; checker->dump_func = dump_func; checker->launch = launch; checker->vs = vs; checker->rs = rs; checker->data = data; checker->co = co; checker->id = ncheckers++; checker->enabled = (vs->vfwmark) ? 1 : 0; checker->warmup = vs->delay_loop; #ifdef _WITHOUT_VRRP_ checker->enabled = 1; #endif /* queue the checker */ list_add(checkers_queue, checker); /* In Alpha mode also mark the check as failed. */ if (vs->alpha) { list fc = rs->failed_checkers; checker_id_t *id = (checker_id_t *) MALLOC(sizeof(checker_id_t)); *id = checker->id; list_add (fc, id); } } /* Set dst */ void checker_set_dst(struct sockaddr_storage *dst) { virtual_server_t *vs = LIST_TAIL_DATA(check_data->vs); real_server_t *rs = LIST_TAIL_DATA(vs->rs); *dst = rs->addr; } void checker_set_dst_port(struct sockaddr_storage *dst, uint16_t port) { if (dst->ss_family == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) dst; addr6->sin6_port = port; } else { struct sockaddr_in *addr4 = (struct sockaddr_in *) dst; addr4->sin_port = port; } } /* "connect_ip" keyword */ static void co_ip_handler(vector_t *strvec) { conn_opts_t *co = CHECKER_GET_CO(); inet_stosockaddr(vector_slot(strvec, 1), 0, &co->dst); } /* "connect_port" keyword */ static void co_port_handler(vector_t *strvec) { conn_opts_t *co = CHECKER_GET_CO(); checker_set_dst_port(&co->dst, htons(CHECKER_VALUE_INT(strvec))); } /* "bindto" keyword */ static void co_srcip_handler(vector_t *strvec) { conn_opts_t *co = CHECKER_GET_CO(); inet_stosockaddr(vector_slot(strvec, 1), 0, &co->bindto); } /* "bind_port" keyword */ static void co_srcport_handler(vector_t *strvec) { conn_opts_t *co = CHECKER_GET_CO(); checker_set_dst_port(&co->bindto, htons(CHECKER_VALUE_INT(strvec))); } /* "connect_timeout" keyword */ static void co_timeout_handler(vector_t *strvec) { conn_opts_t *co = CHECKER_GET_CO(); co->connection_to = CHECKER_VALUE_INT(strvec) * TIMER_HZ; /* do not allow 0 timeout */ if (! co->connection_to) co->connection_to = TIMER_HZ; } #ifdef _WITH_SO_MARK_ /* "fwmark" keyword */ static void co_fwmark_handler(vector_t *strvec) { conn_opts_t *co = CHECKER_GET_CO(); co->fwmark = CHECKER_VALUE_INT(strvec); } #endif void install_connect_keywords(void) { install_keyword("connect_ip", &co_ip_handler); install_keyword("connect_port", &co_port_handler); install_keyword("bindto", &co_srcip_handler); install_keyword("bind_port", &co_srcport_handler); install_keyword("connect_timeout", &co_timeout_handler); #ifdef _WITH_SO_MARK_ install_keyword("fwmark", &co_fwmark_handler); #endif } /* "warmup" keyword */ void warmup_handler(vector_t *strvec) { checker_t *checker = CHECKER_GET_CURRENT(); checker->warmup = (long)CHECKER_VALUE_INT (strvec) * TIMER_HZ; } /* dump the checkers_queue */ void dump_checkers_queue(void) { if (!LIST_ISEMPTY(checkers_queue)) { log_message(LOG_INFO, "------< Health checkers >------"); dump_list(checkers_queue); } } /* init the global checkers queue */ void init_checkers_queue(void) { checkers_queue = alloc_list(free_checker, dump_checker); } /* release the checkers_queue */ void free_checkers_queue(void) { free_list(checkers_queue); checkers_queue = NULL; ncheckers = 0; } /* register checkers to the global I/O scheduler */ void register_checkers_thread(void) { checker_t *checker; element e; long warmup; for (e = LIST_HEAD(checkers_queue); e; ELEMENT_NEXT(e)) { checker = ELEMENT_DATA(e); log_message(LOG_INFO, "Activating healthchecker for service %s" , FMT_CHK(checker)); CHECKER_ENABLE(checker); if (checker->launch) { /* wait for a random timeout to begin checker thread. It helps avoiding multiple simultaneous checks to the same RS. */ warmup = checker->warmup; if (warmup) warmup = warmup * rand() / RAND_MAX; thread_add_timer(master, checker->launch, checker, BOOTSTRAP_DELAY + warmup); } } } /* Sync checkers activity with netlink kernel reflection */ void update_checker_activity(sa_family_t family, void *address, int enable) { checker_t *checker; sa_family_t vip_family; element e; char addr_str[INET6_ADDRSTRLEN]; void *addr; /* Display netlink operation */ if (debug & 32) { inet_ntop(family, address, addr_str, sizeof(addr_str)); log_message(LOG_INFO, "Netlink reflector reports IP %s %s" , addr_str, (enable) ? "added" : "removed"); } /* Processing Healthcheckers queue */ if (!LIST_ISEMPTY(checkers_queue)) { for (e = LIST_HEAD(checkers_queue); e; ELEMENT_NEXT(e)) { checker = ELEMENT_DATA(e); vip_family = checker->vs->addr.ss_family; if (vip_family != family) continue; if (family == AF_INET6) { addr = (void *) &((struct sockaddr_in6 *)&checker->vs->addr)->sin6_addr; } else { addr = (void *) &((struct sockaddr_in *)&checker->vs->addr)->sin_addr; } if (inaddr_equal(family, addr, address) && CHECKER_HA_SUSPEND(checker)) { if (!CHECKER_ENABLED(checker) && enable) log_message(LOG_INFO, "Activating healthchecker for service %s" , FMT_CHK(checker)); if (CHECKER_ENABLED(checker) && !enable) log_message(LOG_INFO, "Suspending healthchecker for service %s" , FMT_CHK(checker)); checker->enabled = enable; } } } } /* Install checkers keywords */ void install_checkers_keyword(void) { install_misc_check_keyword(); install_smtp_check_keyword(); install_tcp_check_keyword(); install_http_check_keyword(); install_ssl_check_keyword(); } keepalived-1.2.13/keepalived/check/check_http.c0000644000175000017500000005752112334072037021204 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: WEB CHECK. Common HTTP/SSL checker primitives. * * Authors: Alexandre Cassen, * Jan Holmberg, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include #include "check_http.h" #include "check_ssl.h" #include "check_api.h" #include "logger.h" #include "memory.h" #include "parser.h" #include "utils.h" #include "html.h" int http_connect_thread(thread_t *); /* Configuration stream handling */ void free_url(void *data) { url_t *url = data; FREE(url->path); FREE(url->digest); FREE(url); } void dump_url(void *data) { url_t *url = data; log_message(LOG_INFO, " Checked url = %s", url->path); if (url->digest) log_message(LOG_INFO, " digest = %s", url->digest); if (url->status_code) log_message(LOG_INFO, " HTTP Status Code = %d", url->status_code); } void free_http_get_check(void *data) { http_checker_t *http_get_chk = CHECKER_DATA(data); free_list(http_get_chk->url); FREE(http_get_chk->arg); FREE(http_get_chk); FREE(CHECKER_CO(data)); FREE(data); } void dump_http_get_check(void *data) { http_checker_t *http_get_chk = CHECKER_DATA(data); if (http_get_chk->proto == PROTO_HTTP) log_message(LOG_INFO, " Keepalive method = HTTP_GET"); else log_message(LOG_INFO, " Keepalive method = SSL_GET"); dump_conn_opts (CHECKER_GET_CO()); log_message(LOG_INFO, " Nb get retry = %d", http_get_chk->nb_get_retry); log_message(LOG_INFO, " Delay before retry = %lu", http_get_chk->delay_before_retry/TIMER_HZ); dump_list(http_get_chk->url); } static http_checker_t * alloc_http_get(char *proto) { http_checker_t *http_get_chk; http_get_chk = (http_checker_t *) MALLOC(sizeof (http_checker_t)); http_get_chk->arg = (http_t *) MALLOC(sizeof (http_t)); http_get_chk->proto = (!strcmp(proto, "HTTP_GET")) ? PROTO_HTTP : PROTO_SSL; http_get_chk->url = alloc_list(free_url, dump_url); http_get_chk->nb_get_retry = 1; http_get_chk->delay_before_retry = 3 * TIMER_HZ; return http_get_chk; } void http_get_handler(vector_t *strvec) { http_checker_t *http_get_chk; char *str = vector_slot(strvec, 0); /* queue new checker */ http_get_chk = alloc_http_get(str); queue_checker(free_http_get_check, dump_http_get_check, http_connect_thread, http_get_chk, CHECKER_NEW_CO()); } void nb_get_retry_handler(vector_t *strvec) { http_checker_t *http_get_chk = CHECKER_GET(); http_get_chk->nb_get_retry = CHECKER_VALUE_INT(strvec); } void delay_before_retry_handler(vector_t *strvec) { http_checker_t *http_get_chk = CHECKER_GET(); http_get_chk->delay_before_retry = CHECKER_VALUE_INT(strvec) * TIMER_HZ; } void url_handler(vector_t *strvec) { http_checker_t *http_get_chk = CHECKER_GET(); url_t *new; /* allocate the new URL */ new = (url_t *) MALLOC(sizeof (url_t)); list_add(http_get_chk->url, new); } void path_handler(vector_t *strvec) { http_checker_t *http_get_chk = CHECKER_GET(); url_t *url = LIST_TAIL_DATA(http_get_chk->url); url->path = CHECKER_VALUE_STRING(strvec); } void digest_handler(vector_t *strvec) { http_checker_t *http_get_chk = CHECKER_GET(); url_t *url = LIST_TAIL_DATA(http_get_chk->url); url->digest = CHECKER_VALUE_STRING(strvec); } void status_code_handler(vector_t *strvec) { http_checker_t *http_get_chk = CHECKER_GET(); url_t *url = LIST_TAIL_DATA(http_get_chk->url); url->status_code = CHECKER_VALUE_INT(strvec); } void install_http_check_keyword(void) { install_keyword("HTTP_GET", &http_get_handler); install_sublevel(); install_connect_keywords(); install_keyword("warmup", &warmup_handler); install_keyword("nb_get_retry", &nb_get_retry_handler); install_keyword("delay_before_retry", &delay_before_retry_handler); install_keyword("url", &url_handler); install_sublevel(); install_keyword("path", &path_handler); install_keyword("digest", &digest_handler); install_keyword("status_code", &status_code_handler); install_sublevel_end(); install_sublevel_end(); } /* a little code duplication :/ */ void install_ssl_check_keyword(void) { install_keyword("SSL_GET", &http_get_handler); install_sublevel(); install_connect_keywords(); install_keyword("warmup", &warmup_handler); install_keyword("nb_get_retry", &nb_get_retry_handler); install_keyword("delay_before_retry", &delay_before_retry_handler); install_keyword("url", &url_handler); install_sublevel(); install_keyword("path", &path_handler); install_keyword("digest", &digest_handler); install_keyword("status_code", &status_code_handler); install_sublevel_end(); install_sublevel_end(); } /* * The global design of this checker is the following : * * - All the actions are done asynchronously. * - All the actions handle timeout connection. * - All the actions handle error from low layer to upper * layers. * * The global synopsis of the inter-thread-call is : * * http_connect_thread (handle layer4 connect) * v * http_check_thread (handle SSL connect) * v * http_request_thread (send SSL GET request) * v * http_response_thread (initialize read stream step) * / \ * / \ * v v * http_read_thread ssl_read_thread (perform HTTP|SSL stream) * v v * http_handle_response (next checker thread registration) */ /* * Simple epilog functions. Handling event timeout. * Finish the checker with memory managment or url rety check. * * c == 0 => reset to 0 retry_it counter * t == 0 => reset to 0 url_it counter * method == 1 => register a new checker thread * method == 2 => register a retry on url checker thread */ int epilog(thread_t * thread, int method, int t, int c) { checker_t *checker = THREAD_ARG(thread); http_checker_t *http_get_check = CHECKER_ARG(checker); http_t *http = HTTP_ARG(http_get_check); request_t *req = HTTP_REQ(http); long delay = 0; if (method) { http->url_it += t ? t : -http->url_it; http->retry_it += c ? c : -http->retry_it; } /* * The get retry implementation mean that we retry performing * a GET on the same url until the remote web server return * html buffer. This is sometime needed with some applications * servers. */ if (http->retry_it > http_get_check->nb_get_retry-1) { if (svr_checker_up(checker->id, checker->rs)) { log_message(LOG_INFO, "Check on service %s failed after %d retry." , FMT_HTTP_RS(checker)); smtp_alert(checker->rs, NULL, NULL, "DOWN", "=> CHECK failed on service" " : MD5 digest mismatch <="); update_svr_checker_state(DOWN, checker->id , checker->vs , checker->rs); } /* Reset it counters */ http->url_it = 0; http->retry_it = 0; } /* register next timer thread */ switch (method) { case 1: if (req) delay = checker->vs->delay_loop; else delay = http_get_check->delay_before_retry; break; case 2: if (http->url_it == 0 && http->retry_it == 0) delay = checker->vs->delay_loop; else delay = http_get_check->delay_before_retry; break; } /* If req == NULL, fd is not created */ if (req) { if (req->ssl) SSL_free(req->ssl); if (req->buffer) FREE(req->buffer); FREE(req); http->req = NULL; close(thread->u.fd); } /* Register next checker thread */ thread_add_timer(thread->master, http_connect_thread, checker, delay); return 0; } int timeout_epilog(thread_t * thread, char *smtp_msg, char *debug_msg) { checker_t *checker = THREAD_ARG(thread); log_message(LOG_INFO, "Timeout %s server %s." , debug_msg , FMT_HTTP_RS(checker)); /* check if server is currently alive */ if (svr_checker_up(checker->id, checker->rs)) { smtp_alert(checker->rs, NULL, NULL, "DOWN", smtp_msg); update_svr_checker_state(DOWN, checker->id , checker->vs , checker->rs); } return epilog(thread, 1, 0, 0); } /* return the url pointer of the current url iterator */ url_t * fetch_next_url(http_checker_t * http_get_check) { http_t *http = HTTP_ARG(http_get_check); return list_element(http_get_check->url, http->url_it); } /* Handle response */ int http_handle_response(thread_t * thread, unsigned char digest[16] , int empty_buffer) { checker_t *checker = THREAD_ARG(thread); http_checker_t *http_get_check = CHECKER_ARG(checker); http_t *http = HTTP_ARG(http_get_check); request_t *req = HTTP_REQ(http); int r, di = 0; char *digest_tmp; url_t *fetched_url = fetch_next_url(http_get_check); enum { none, on_status, on_digest } last_success = none; /* the source of last considered success */ /* First check if remote webserver returned data */ if (empty_buffer) return timeout_epilog(thread, "=> CHECK failed on service" " : empty buffer received <=\n\n", "Read, no data received from "); /* Next check the HTTP status code */ if (fetched_url->status_code) { if (req->status_code != fetched_url->status_code) { /* check if server is currently alive */ if (svr_checker_up(checker->id, checker->rs)) { log_message(LOG_INFO, "HTTP status code error to %s url(%s)" ", status_code [%d].", FMT_HTTP_RS(checker), fetched_url->path, req->status_code); smtp_alert(checker->rs, NULL, NULL, "DOWN", "=> CHECK failed on service" " : HTTP status code mismatch <="); update_svr_checker_state(DOWN, checker->id , checker->vs , checker->rs); } else { DBG("HTTP Status_code to %s url(%d) = [%d]." , FMT_HTTP_RS(checker) , http->url_it + 1 , req->status_code); /* * We set retry iterator to max value to not retry * when service is already know as die. */ http->retry_it = http_get_check->nb_get_retry; } return epilog(thread, 2, 0, 1); } else { last_success = on_status; } } /* Continue with MD5SUM */ if (fetched_url->digest) { /* Compute MD5SUM */ digest_tmp = (char *) MALLOC(MD5_BUFFER_LENGTH + 1); for (di = 0; di < 16; di++) sprintf(digest_tmp + 2 * di, "%02x", digest[di]); r = strcmp(fetched_url->digest, digest_tmp); if (r) { /* check if server is currently alive */ if (svr_checker_up(checker->id, checker->rs)) { log_message(LOG_INFO, "MD5 digest error to %s url[%s]" ", MD5SUM [%s].", FMT_HTTP_RS(checker), fetched_url->path, digest_tmp); smtp_alert(checker->rs, NULL, NULL, "DOWN", "=> CHECK failed on service" " : HTTP MD5SUM mismatch <="); update_svr_checker_state(DOWN, checker->id , checker->vs , checker->rs); } else { DBG("MD5SUM to %s url(%d) = [%s]." , FMT_HTTP_RS(checker) , http->url_it + 1 , digest_tmp); /* * We set retry iterator to max value to not retry * when service is already know as die. */ http->retry_it = http_get_check->nb_get_retry; } FREE(digest_tmp); return epilog(thread, 2, 0, 1); } else { last_success = on_digest; FREE(digest_tmp); } } if (!svr_checker_up(checker->id, checker->rs)) { switch (last_success) { case none: break; case on_status: log_message(LOG_INFO, "HTTP status code success to %s url(%d)." , FMT_HTTP_RS(checker) , http->url_it + 1); return epilog(thread, 1, 1, 0) + 1; case on_digest: if (!svr_checker_up(checker->id, checker->rs)) log_message(LOG_INFO, "MD5 digest success to %s url(%d)." , FMT_HTTP_RS(checker) , http->url_it + 1); return epilog(thread, 1, 1, 0) + 1; } } return epilog(thread, 1, 0, 0) + 1; } /* Handle response stream performing MD5 updates */ int http_process_response(request_t *req, int r) { req->len += r; if (!req->extracted) { if ((req->extracted = extract_html(req->buffer, req->len))) { req->status_code = extract_status_code(req->buffer, req->len); r = req->len - (req->extracted - req->buffer); if (r) { memmove(req->buffer, req->extracted, r); MD5_Update(&req->context, req->buffer, r); r = 0; } req->len = r; } } else if (req->len) { MD5_Update(&req->context, req->buffer, req->len); req->len = 0; } return 0; } /* Asynchronous HTTP stream reader */ int http_read_thread(thread_t * thread) { checker_t *checker = THREAD_ARG(thread); http_checker_t *http_get_check = CHECKER_ARG(checker); http_t *http = HTTP_ARG(http_get_check); request_t *req = HTTP_REQ(http); unsigned timeout = checker->co->connection_to; unsigned char digest[16]; int r = 0; int val; /* Handle read timeout */ if (thread->type == THREAD_READ_TIMEOUT) return timeout_epilog(thread, "=> HTTP CHECK failed on service" " : recevice data <=\n\n", "HTTP read"); /* Set descriptor non blocking */ val = fcntl(thread->u.fd, F_GETFL, 0); fcntl(thread->u.fd, F_SETFL, val | O_NONBLOCK); /* read the HTTP stream */ r = read(thread->u.fd, req->buffer + req->len, MAX_BUFFER_LENGTH - req->len); /* restore descriptor flags */ fcntl(thread->u.fd, F_SETFL, val); /* Test if data are ready */ if (r == -1 && (errno == EAGAIN || errno == EINTR)) { log_message(LOG_INFO, "Read error with server %s: %s" , FMT_HTTP_RS(checker) , strerror(errno)); thread_add_read(thread->master, http_read_thread, checker, thread->u.fd, timeout); return 0; } if (r == -1 || r == 0) { /* -1:error , 0:EOF */ /* All the HTTP stream has been parsed */ MD5_Final(digest, &req->context); if (r == -1) { /* We have encourred a real read error */ if (svr_checker_up(checker->id, checker->rs)) { log_message(LOG_INFO, "Read error with server %s: %s" , FMT_HTTP_RS(checker) , strerror(errno)); smtp_alert(checker->rs, NULL, NULL, "DOWN", "=> HTTP CHECK failed on service" " : cannot receive data <="); update_svr_checker_state(DOWN, checker->id , checker->vs , checker->rs); } return epilog(thread, 1, 0, 0); } /* Handle response stream */ http_handle_response(thread, digest, (!req->extracted) ? 1 : 0); } else { /* Handle response stream */ http_process_response(req, r); /* * Register next http stream reader. * Register itself to not perturbe global I/O multiplexer. */ thread_add_read(thread->master, http_read_thread, checker, thread->u.fd, timeout); } return 0; } /* * Read get result from the remote web server. * Apply trigger check to this result. */ int http_response_thread(thread_t * thread) { checker_t *checker = THREAD_ARG(thread); http_checker_t *http_get_check = CHECKER_ARG(checker); http_t *http = HTTP_ARG(http_get_check); request_t *req = HTTP_REQ(http); unsigned timeout = checker->co->connection_to; /* Handle read timeout */ if (thread->type == THREAD_READ_TIMEOUT) return timeout_epilog(thread, "=> CHECK failed on service" " : recevice data <=\n\n", "WEB read"); /* Allocate & clean the get buffer */ req->buffer = (char *) MALLOC(MAX_BUFFER_LENGTH); req->extracted = NULL; req->len = 0; req->error = 0; MD5_Init(&req->context); /* Register asynchronous http/ssl read thread */ if (http_get_check->proto == PROTO_SSL) thread_add_read(thread->master, ssl_read_thread, checker, thread->u.fd, timeout); else thread_add_read(thread->master, http_read_thread, checker, thread->u.fd, timeout); return 0; } /* remote Web server is connected, send it the get url query. */ int http_request_thread(thread_t * thread) { checker_t *checker = THREAD_ARG(thread); http_checker_t *http_get_check = CHECKER_ARG(checker); http_t *http = HTTP_ARG(http_get_check); request_t *req = HTTP_REQ(http); struct sockaddr_storage *addr = &checker->co->dst; unsigned timeout = checker->co->connection_to; char *vhost = CHECKER_VHOST(checker); char *request_host = 0; char *request_host_port = 0; char *str_request; url_t *fetched_url; int ret = 0; int val; /* Handle read timeout */ if (thread->type == THREAD_WRITE_TIMEOUT) return timeout_epilog(thread, "=> CHECK failed on service" " : read timeout <=\n\n", "Web read, timeout"); /* Allocate & clean the GET string */ str_request = (char *) MALLOC(GET_BUFFER_LENGTH); fetched_url = fetch_next_url(http_get_check); if (vhost) { /* If vhost was defined we don't need to override it's port */ request_host = vhost; request_host_port = (char*) MALLOC(1); *request_host_port = 0; } else { request_host = inet_sockaddrtos(addr); /* Allocate a buffer for the port string ( ":" [0-9][0-9][0-9][0-9][0-9] "\0" ) */ request_host_port = (char*) MALLOC(7); snprintf(request_host_port, 7, ":%d", ntohs(inet_sockaddrport(addr))); } if(addr->ss_family == AF_INET6 && !vhost){ /* if literal ipv6 address, use ipv6 template, see RFC 2732 */ snprintf(str_request, GET_BUFFER_LENGTH, REQUEST_TEMPLATE_IPV6, fetched_url->path, request_host, request_host_port); } else { snprintf(str_request, GET_BUFFER_LENGTH, REQUEST_TEMPLATE, fetched_url->path, request_host, request_host_port); } FREE(request_host_port); DBG("Processing url(%d) of %s.", http->url_it + 1 , FMT_HTTP_RS(checker)); /* Set descriptor non blocking */ val = fcntl(thread->u.fd, F_GETFL, 0); fcntl(thread->u.fd, F_SETFL, val | O_NONBLOCK); /* Send the GET request to remote Web server */ if (http_get_check->proto == PROTO_SSL) { ret = ssl_send_request(req->ssl, str_request, strlen(str_request)); } else { ret = (send(thread->u.fd, str_request, strlen(str_request), 0) != -1) ? 1 : 0; } /* restore descriptor flags */ fcntl(thread->u.fd, F_SETFL, val); FREE(str_request); if (!ret) { log_message(LOG_INFO, "Cannot send get request to %s." , FMT_HTTP_RS(checker)); /* check if server is currently alive */ if (svr_checker_up(checker->id, checker->rs)) { smtp_alert(checker->rs, NULL, NULL, "DOWN", "=> CHECK failed on service" " : cannot send data <="); update_svr_checker_state(DOWN, checker->id , checker->vs , checker->rs); } return epilog(thread, 1, 0, 0); } /* Register read timeouted thread */ thread_add_read(thread->master, http_response_thread, checker, thread->u.fd, timeout); return 1; } /* WEB checkers threads */ int http_check_thread(thread_t * thread) { checker_t *checker = THREAD_ARG(thread); http_checker_t *http_get_check = CHECKER_ARG(checker); http_t *http = HTTP_ARG(http_get_check); #ifdef _DEBUG_ request_t *req = HTTP_REQ(http); #endif int ret = 1; int status; long timeout = 0; int ssl_err = 0; int new_req = 0; status = tcp_socket_state(thread->u.fd, thread, http_check_thread); switch (status) { case connect_error: /* check if server is currently alive */ if (svr_checker_up(checker->id, checker->rs)) { log_message(LOG_INFO, "Error connecting server %s." , FMT_HTTP_RS(checker)); smtp_alert(checker->rs, NULL, NULL, "DOWN", "=> CHECK failed on service" " : connection error <="); update_svr_checker_state(DOWN, checker->id , checker->vs , checker->rs); } return epilog(thread, 1, 0, 0); break; case connect_timeout: return timeout_epilog(thread, "==> CHECK failed on service" " : connection timeout <=\n\n", "connect, timeout"); break; case connect_success:{ if (!http->req) { http->req = (request_t *) MALLOC(sizeof (request_t)); new_req = 1; } else new_req = 0; if (http_get_check->proto == PROTO_SSL) { timeout = timer_long(thread->sands) - timer_long(time_now); if (thread->type != THREAD_WRITE_TIMEOUT && thread->type != THREAD_READ_TIMEOUT) ret = ssl_connect(thread, new_req); else { return timeout_epilog(thread, "==> CHECK failed on service" " : connection timeout <=\n\n", "connect, timeout"); } if (ret == -1) { switch ((ssl_err = SSL_get_error(http->req->ssl, ret))) { case SSL_ERROR_WANT_READ: thread_add_read(thread->master, http_check_thread, THREAD_ARG(thread), thread->u.fd, timeout); break; case SSL_ERROR_WANT_WRITE: thread_add_write(thread->master, http_check_thread, THREAD_ARG(thread), thread->u.fd, timeout); break; default: ret = 0; break; } if (ret == -1) break; } else if (ret != 1) ret = 0; } if (ret) { /* Remote WEB server is connected. * Register the next step thread ssl_request_thread. */ DBG("Remote Web server %s connected.", FMT_HTTP_RS(checker)); thread_add_write(thread->master, http_request_thread, checker, thread->u.fd, checker->co->connection_to); } else { DBG("Connection trouble to: %s." , FMT_HTTP_RS(checker)); #ifdef _DEBUG_ if (http_get_check->proto == PROTO_SSL) ssl_printerr(SSL_get_error (req->ssl, ret)); #endif if ((http_get_check->proto == PROTO_SSL) && (svr_checker_up(checker->id, checker->rs))) { log_message(LOG_INFO, "SSL handshake/communication error" " connecting to server" " (openssl errno: %d) %s." , SSL_get_error (http->req->ssl, ret) , FMT_HTTP_RS(checker)); smtp_alert(checker->rs, NULL, NULL, "DOWN", "=> CHECK failed on service" " : SSL connection error <="); update_svr_checker_state(DOWN, checker->id , checker->vs , checker->rs); } return epilog(thread, 1, 0, 0); } } break; } return 0; } int http_connect_thread(thread_t * thread) { checker_t *checker = THREAD_ARG(thread); http_checker_t *http_get_check = CHECKER_ARG(checker); http_t *http = HTTP_ARG(http_get_check); conn_opts_t *co = checker->co; url_t *fetched_url; enum connect_result status; int fd; /* * Register a new checker thread & return * if checker is disabled */ if (!CHECKER_ENABLED(checker)) { thread_add_timer(thread->master, http_connect_thread, checker, checker->vs->delay_loop); return 0; } /* Find eventual url end */ fetched_url = fetch_next_url(http_get_check); if (!fetched_url) { /* All the url have been successfully checked. * Check completed. * check if server is currently alive. */ if (!svr_checker_up(checker->id, checker->rs)) { log_message(LOG_INFO, "Remote Web server %s succeed on service." , FMT_HTTP_RS(checker)); smtp_alert(checker->rs, NULL, NULL, "UP", "=> CHECK succeed on service <="); update_svr_checker_state(UP, checker->id , checker->vs , checker->rs); } http->req = NULL; return epilog(thread, 1, 0, 0) + 1; } /* Create the socket */ if ((fd = socket(co->dst.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { log_message(LOG_INFO, "WEB connection fail to create socket. Rescheduling."); thread_add_timer(thread->master, http_connect_thread, checker, checker->vs->delay_loop); return 0; } status = tcp_bind_connect(fd, co); /* handle tcp connection status & register check worker thread */ if(tcp_connection_state(fd, status, thread, http_check_thread, co->connection_to)) { close(fd); log_message(LOG_INFO, "WEB socket bind failed. Rescheduling"); thread_add_timer(thread->master, http_connect_thread, checker, checker->vs->delay_loop); } return 0; } keepalived-1.2.13/keepalived/check/check_smtp.c0000644000175000017500000005652012334072037021206 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: SMTP CHECK. Check an SMTP-server. * * Authors: Jeremy Rumpf, * Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include #include "check_smtp.h" #include "check_api.h" #include "logger.h" #include "memory.h" #include "ipwrapper.h" #include "utils.h" #include "parser.h" #include "daemon.h" int smtp_connect_thread(thread_t *); /* module variables */ static smtp_host_t *default_host = NULL; /* * Used as a callback from free_list() to free all * the list elements in smtp_checker->host before we * free smtp_checker itself. */ void smtp_free_host(void *data) { FREE(data); } /* Used as a callback from the checker api, queue_checker(), * to free up a checker entry and all its associated data. */ void free_smtp_check(void *data) { smtp_checker_t *smtp_checker = CHECKER_DATA(data); free_list(smtp_checker->host); FREE(smtp_checker->helo_name); FREE(smtp_checker); FREE(data); } /* * Used as a callback from dump_list() to print out all * the list elements in smtp_checker->host. */ void smtp_dump_host(void *data) { dump_conn_opts (data); } /* * Callback for whenever we've been requested to dump our * configuration. */ void dump_smtp_check(void *data) { smtp_checker_t *smtp_checker = CHECKER_DATA(data); log_message(LOG_INFO, " Keepalive method = SMTP_CHECK"); log_message(LOG_INFO, " helo = %s", smtp_checker->helo_name); log_message(LOG_INFO, " timeout = %ld", smtp_checker->timeout/TIMER_HZ); log_message(LOG_INFO, " retry = %d", smtp_checker->retry); log_message(LOG_INFO, " delay before retry = %ld", smtp_checker->db_retry/TIMER_HZ); dump_list(smtp_checker->host); } /* Allocates a default host structure */ smtp_host_t * smtp_alloc_host(void) { smtp_host_t *new; smtp_checker_t *smtp_checker = CHECKER_GET(); /* Allocate the new host data structure */ new = (smtp_host_t *)MALLOC(sizeof(smtp_host_t)); /* * By default we set the ip to connect to as the same ip as the current real server * in the rs config. This might be overridden later on by a "connect_ip" keyword. */ checker_set_dst(&new->dst); checker_set_dst_port(&new->dst, htons(SMTP_DEFAULT_PORT)); new->connection_to = smtp_checker->timeout; return new; } /* * Callback for whenever an SMTP_CHECK keyword is encountered * in the config file. */ void smtp_check_handler(vector_t *strvec) { smtp_checker_t *smtp_checker = (smtp_checker_t *)MALLOC(sizeof(smtp_checker_t)); /* * Set something sane for the default HELO banner * May be overridden by a "helo_name" keyword later. */ smtp_checker->helo_name = (char *)MALLOC(strlen(SMTP_DEFAULT_HELO) + 1); memcpy(smtp_checker->helo_name, SMTP_DEFAULT_HELO, strlen(SMTP_DEFAULT_HELO) + 1); /* some other sane values */ smtp_checker->timeout = 5 * TIMER_HZ; smtp_checker->db_retry = 1 * TIMER_HZ; smtp_checker->retry = 1; /* * Have the checker queue code put our checker into the checkers_queue * list. * * queue_checker(void (*free) (void *), void (*dump) (void *), * int (*launch) (thread_t *), * void *data, conn_opts_t *) */ queue_checker(free_smtp_check, dump_smtp_check, smtp_connect_thread, smtp_checker, NULL); /* * Last, allocate/setup the list that will hold all the per host * configuration structures. We'll set a "default host", which * is the same ip as the real server. If there are additional "host" * sections in the config, the default will be deleted and overridden. * If the default is still set by a previous "SMTP_CHECK" section, * we must simply overwrite the old value: * - it must not be reused, because it was probably located in a * different "real_server" section and * - it must not be freed, because it is still referenced * by some other smtp_checker->host. * This must come after queue_checker()! */ smtp_checker->host = alloc_list(smtp_free_host, smtp_dump_host); default_host = smtp_alloc_host(); list_add(smtp_checker->host, default_host); } /* * Callback for whenever the "host" keyword is encountered * in the config file. */ void smtp_host_handler(vector_t *strvec) { smtp_checker_t *smtp_checker = CHECKER_GET(); /* * If the default host is still allocated, delete it * before we stick user defined hosts in the list. */ if (default_host) { list_del(smtp_checker->host, default_host); FREE(default_host); default_host = NULL; } /* add an empty host to the list, smtp_checker->host */ list_add(smtp_checker->host, smtp_alloc_host()); } /* "helo_name" keyword */ void smtp_helo_name_handler(vector_t *strvec) { smtp_checker_t *smtp_checker = CHECKER_GET(); smtp_checker->helo_name = CHECKER_VALUE_STRING(strvec); } /* "connect_timeout" keyword */ void smtp_timeout_handler(vector_t *strvec) { smtp_checker_t *smtp_checker = CHECKER_GET(); smtp_checker->timeout = CHECKER_VALUE_INT(strvec) * TIMER_HZ; if (smtp_checker->timeout < TIMER_HZ) smtp_checker->timeout = TIMER_HZ; } /* "retry" keyword */ void smtp_retry_handler(vector_t *strvec) { smtp_checker_t *smtp_checker = CHECKER_GET(); smtp_checker->retry = CHECKER_VALUE_INT(strvec); } /* "delay_before_retry" keyword */ void smtp_db_retry_handler(vector_t *strvec) { smtp_checker_t *smtp_checker = CHECKER_GET(); smtp_checker->db_retry = CHECKER_VALUE_INT(strvec) * TIMER_HZ; } /* Config callback installer */ void install_smtp_check_keyword(void) { /* * Notify the config log parser that we need to be notified via * callbacks when the following keywords are encountered in the * keepalive.conf file. */ install_keyword("SMTP_CHECK", &smtp_check_handler); install_sublevel(); install_keyword("helo_name", &smtp_helo_name_handler); /* This is kept for backward compatibility. Used as default value for per-host timeout */ install_keyword("connect_timeout", &smtp_timeout_handler); install_keyword("warmup", &warmup_handler); install_keyword("delay_before_retry", &smtp_db_retry_handler); install_keyword("retry", &smtp_retry_handler); install_keyword("host", &smtp_host_handler); install_sublevel(); install_connect_keywords(); install_sublevel_end(); install_sublevel_end(); } /* * Final handler. Determines if we need a retry or not. * Also has to make a decision if we need to bring the resulting * service down in case of error. */ int smtp_final(thread_t *thread, int error, const char *format, ...) { checker_t *checker = THREAD_ARG(thread); smtp_checker_t *smtp_checker = CHECKER_ARG(checker); char error_buff[512]; char smtp_buff[542]; va_list varg_list; /* Error or no error we should always have to close the socket */ close(thread->u.fd); /* If we're here, an attempt HAS been made already for the current host */ smtp_checker->attempts++; if (error) { /* Always syslog the error when the real server is up */ if (svr_checker_up(checker->id, checker->rs)) { if (format != NULL) { memcpy(error_buff, "SMTP_CHECK ", 11); va_start(varg_list, format); vsnprintf(error_buff + 11, 512 - 11, format, varg_list); va_end(varg_list); error_buff[512 - 1] = '\0'; log_message(LOG_INFO, error_buff); } else { log_message(LOG_INFO, "SMTP_CHECK Unknown error"); } } /* * If we still have retries left, try this host again by * scheduling the main thread to check it again after the * configured backoff delay. Otherwise down the RS. */ if (smtp_checker->attempts < smtp_checker->retry) { thread_add_timer(thread->master, smtp_connect_thread, checker, smtp_checker->db_retry); return 0; } /* * No more retries, pull the real server from the virtual server. * Only smtp_alert if it wasn't previously down. It should * be noted that smtp_alert makes a copy of the string arguments, so * we don't have to keep them statically allocated. */ if (svr_checker_up(checker->id, checker->rs)) { if (format != NULL) { snprintf(smtp_buff, 542, "=> CHECK failed on service : %s <=", error_buff + 11); } else { snprintf(smtp_buff, 542, "=> CHECK failed on service <="); } smtp_buff[542 - 1] = '\0'; smtp_alert(checker->rs, NULL, NULL, "DOWN", smtp_buff); update_svr_checker_state(DOWN, checker->id, checker->vs, checker->rs); } /* Reset everything back to the first host in the list */ smtp_checker->attempts = 0; smtp_checker->host_ctr = 0; /* Reschedule the main thread using the configured delay loop */; thread_add_timer(thread->master, smtp_connect_thread, checker, checker->vs->delay_loop); return 0; } /* * Ok this host was successful, increment to the next host in the list * and reset the attempts counter. We'll then reschedule the main thread again. * If host_ctr exceeds the number of hosts in the list, http_main_thread will * take note and bring up the real server as well as inject the delay_loop. */ smtp_checker->attempts = 0; smtp_checker->host_ctr++; thread_add_timer(thread->master, smtp_connect_thread, checker, 1); return 0; } /* * Zeros out the rx/tx buffer */ void smtp_clear_buff(thread_t *thread) { checker_t *checker = THREAD_ARG(thread); smtp_checker_t *smtp_checker = CHECKER_ARG(checker); memset(smtp_checker->buff, 0, SMTP_BUFF_MAX); smtp_checker->buff_ctr = 0; } /* * One thing to note here is we do a very cheap check for a newline. * We could receive two lines (with two newline characters) in a * single packet, but we don't care. We are only looking at the * SMTP response codes at the beginning anyway. */ int smtp_get_line_cb(thread_t *thread) { checker_t *checker = THREAD_ARG(thread); smtp_checker_t *smtp_checker = CHECKER_ARG(checker); smtp_host_t *smtp_host = smtp_checker->host_ptr; int f, r, x; /* Handle read timeout */ if (thread->type == THREAD_READ_TIMEOUT) { smtp_final(thread, 1, "Read timeout from server %s" , FMT_SMTP_RS(smtp_host)); return 0; } /* wrap the buffer, if full, by clearing it */ if (SMTP_BUFF_MAX - smtp_checker->buff_ctr <= 0) { log_message(LOG_INFO, "SMTP_CHECK Buffer overflow reading from server %s. " "Increase SMTP_BUFF_MAX in smtp_check.h" , FMT_SMTP_RS(smtp_host)); smtp_clear_buff(thread); } /* Set descriptor non blocking */ f = fcntl(thread->u.fd, F_GETFL, 0); fcntl(thread->u.fd, F_SETFL, f | O_NONBLOCK); /* read the data */ r = read(thread->u.fd, smtp_checker->buff + smtp_checker->buff_ctr, SMTP_BUFF_MAX - smtp_checker->buff_ctr); if (r == -1 && (errno == EAGAIN || errno == EINTR)) { thread_add_read(thread->master, smtp_get_line_cb, checker, thread->u.fd, smtp_host->connection_to); fcntl(thread->u.fd, F_SETFL, f); return 0; } else if (r > 0) smtp_checker->buff_ctr += r; /* restore descriptor flags */ fcntl(thread->u.fd, F_SETFL, f); /* check if we have a newline, if so, callback */ for (x = 0; x < SMTP_BUFF_MAX; x++) { if (smtp_checker->buff[x] == '\n') { smtp_checker->buff[SMTP_BUFF_MAX - 1] = '\0'; DBG("SMTP_CHECK %s < %s" , FMT_SMTP_RS(smtp_host) , smtp_checker->buff); (smtp_checker->buff_cb)(thread); return 0; } } /* * If the connection was closed or there was * some sort of error, notify smtp_final() */ if (r <= 0) { smtp_final(thread, 1, "Read failure from server %s" , FMT_SMTP_RS(smtp_host)); return 0; } /* * Last case, we haven't read enough data yet * to pull a newline. Schedule ourselves for * another round. */ thread_add_read(thread->master, smtp_get_line_cb, checker, thread->u.fd, smtp_host->connection_to); return 0; } /* * Ok a caller has asked us to asyncronously schedule a single line * to be received from the server. They have also passed us a call back * function that we'll call once we have the newline. If something bad * happens, the caller assumes we'll pass the error off to smtp_final(), * which will either down the real server or schedule a retry. The * function smtp_get_line_cb is what does the dirty work since the * sceduler can only accept a single *thread argument. */ void smtp_get_line(thread_t *thread, int (*callback) (thread_t *)) { checker_t *checker = THREAD_ARG(thread); smtp_checker_t *smtp_checker = CHECKER_ARG(checker); smtp_host_t *smtp_host = smtp_checker->host_ptr; /* clear the buffer */ smtp_clear_buff(thread); /* set the callback */ smtp_checker->buff_cb = callback; /* schedule the I/O with our helper function */ thread_add_read(thread->master, smtp_get_line_cb, checker, thread->u.fd, smtp_host->connection_to); return; } /* * The scheduler function that puts the data out on the wire. * All our data will fit into one packet, so we only check if * the current write would block or not. If it wants to block, * we'll return to the scheduler and try again later. */ int smtp_put_line_cb(thread_t *thread) { checker_t *checker = THREAD_ARG(thread); smtp_checker_t *smtp_checker = CHECKER_ARG(checker); smtp_host_t *smtp_host = smtp_checker->host_ptr; int f, w; /* Handle read timeout */ if (thread->type == THREAD_WRITE_TIMEOUT) { smtp_final(thread, 1, "Write timeout to server %s" , FMT_SMTP_RS(smtp_host)); return 0; } /* Set descriptor non blocking */ f = fcntl(thread->u.fd, F_GETFL, 0); fcntl(thread->u.fd, F_SETFL, f | O_NONBLOCK); /* write the data */ w = write(thread->u.fd, smtp_checker->buff, smtp_checker->buff_ctr); if (w == -1 && (errno == EAGAIN || errno == EINTR)) { thread_add_write(thread->master, smtp_put_line_cb, checker, thread->u.fd, smtp_host->connection_to); fcntl(thread->u.fd, F_SETFL, f); return 0; } /* restore descriptor flags */ fcntl(thread->u.fd, F_SETFL, f); DBG("SMTP_CHECK %s > %s" , FMT_SMTP_RS(smtp_host) , smtp_checker->buff); /* * If the connection was closed or there was * some sort of error, notify smtp_final() */ if (w <= 0) { smtp_final(thread, 1, "Write failure to server %s" , FMT_SMTP_RS(smtp_host)); return 0; } /* Execute the callback */ (smtp_checker->buff_cb)(thread); return 0; } /* * This is the same as smtp_get_line() except that we're sending a * line of data instead of receiving one. */ void smtp_put_line(thread_t *thread, int (*callback) (thread_t *)) { checker_t *checker = THREAD_ARG(thread); smtp_checker_t *smtp_checker = CHECKER_ARG(checker); smtp_host_t *smtp_host = smtp_checker->host_ptr; smtp_checker->buff[SMTP_BUFF_MAX - 1] = '\0'; smtp_checker->buff_ctr = strlen(smtp_checker->buff); /* set the callback */ smtp_checker->buff_cb = callback; /* schedule the I/O with our helper function */ thread_add_write(thread->master, smtp_put_line_cb, checker, thread->u.fd, smtp_host->connection_to); return; } /* * Ok, our goal here is to snag the status code out of the * buffer and return it as an integer. If it's not legible, * return -1. */ int smtp_get_status(thread_t *thread) { checker_t *checker = THREAD_ARG(thread); smtp_checker_t *smtp_checker = CHECKER_ARG(checker); char *buff = smtp_checker->buff; /* First make sure they're all digits */ if (isdigit(buff[0]) && isdigit(buff[1]) && isdigit(buff[2])) { /* Truncate the string and convert */ buff[3] = '\0'; return atoi(buff); } return -1; } /* * We have a connected socket and are ready to begin * the conversation. This function schedules itself to * be called via callbacks and tracking state in * smtp_checker->state. Upon first calling, smtp_checker->state * should be set to SMTP_START. */ int smtp_engine_thread(thread_t *thread) { checker_t *checker = THREAD_ARG(thread); smtp_checker_t *smtp_checker = CHECKER_ARG(checker); smtp_host_t *smtp_host = smtp_checker->host_ptr; switch (smtp_checker->state) { /* First step, schedule to receive the greeting banner */ case SMTP_START: /* * Ok, if smtp_get_line schedules us back, we will * have data to analyze. Otherwise, smtp_get_line * will defer directly to smtp_final. */ smtp_checker->state = SMTP_HAVE_BANNER; smtp_get_line(thread, smtp_engine_thread); return 0; break; /* Second step, analyze banner, send HELO */ case SMTP_HAVE_BANNER: /* Check for "220 some.mailserver.com" in the greeting */ if (smtp_get_status(thread) != 220) { smtp_final(thread, 1, "Bad greeting banner from server %s" , FMT_SMTP_RS(smtp_host)); return 0; } /* * Schedule to send the HELO, smtp_put_line will * defer directly to smtp_final on error. */ smtp_checker->state = SMTP_SENT_HELO; snprintf(smtp_checker->buff, SMTP_BUFF_MAX, "HELO %s\r\n", smtp_checker->helo_name); smtp_put_line(thread, smtp_engine_thread); return 0; break; /* Third step, schedule to read the HELO response */ case SMTP_SENT_HELO: smtp_checker->state = SMTP_RECV_HELO; smtp_get_line(thread, smtp_engine_thread); return 0; break; /* Fourth step, analyze HELO return, send QUIT */ case SMTP_RECV_HELO: /* Check for "250 Please to meet you..." */ if (smtp_get_status(thread) != 250) { smtp_final(thread, 1, "Bad HELO response from server %s" , FMT_SMTP_RS(smtp_host)); return 0; } smtp_checker->state = SMTP_SENT_QUIT; snprintf(smtp_checker->buff, SMTP_BUFF_MAX, "QUIT\r\n"); smtp_put_line(thread, smtp_engine_thread); return 0; break; /* Fifth step, schedule to receive QUIT confirmation */ case SMTP_SENT_QUIT: smtp_checker->state = SMTP_RECV_QUIT; smtp_get_line(thread, smtp_engine_thread); return 0; break; /* Sixth step, wrap up success to smtp_final */ case SMTP_RECV_QUIT: smtp_final(thread, 0, NULL); return 0; break; } /* We shouldn't be here */ smtp_final(thread, 1, "Unknown smtp engine state encountered"); return 0; } /* * Second step in the process. Here we'll see if the connection * to the host we're checking was successful or not. */ int smtp_check_thread(thread_t *thread) { checker_t *checker = THREAD_ARG(thread); smtp_checker_t *smtp_checker = CHECKER_ARG(checker); smtp_host_t *smtp_host = smtp_checker->host_ptr; int status; status = tcp_socket_state(thread->u.fd, thread, smtp_check_thread); switch (status) { case connect_error: smtp_final(thread, 1, "Error connecting to server %s" , FMT_SMTP_RS(smtp_host)); return 0; break; case connect_timeout: smtp_final(thread, 1, "Connection timeout to server %s" , FMT_SMTP_RS(smtp_host)); return 0; break; case connect_success: DBG("SMTP_CHECK Remote SMTP server %s connected" , FMT_SMTP_RS(smtp_host)); /* Enter the engine at SMTP_START */ smtp_checker->state = SMTP_START; smtp_engine_thread(thread); return 0; break; } /* we shouldn't be here */ smtp_final(thread, 1, "Unknown connection error to server %s" , FMT_SMTP_RS(smtp_host)); return 0; } /* * This is the main thread, where all the action starts. * When the check daemon comes up, it goes down the checkers_queue * and launches a thread for each checker that got registered. * This is the callback/event function for that initial thread. * * It should be noted that we ARE responsible for sceduling * ourselves to run again. It doesn't have to be right here, * but eventually has to happen. */ int smtp_connect_thread(thread_t *thread) { checker_t *checker = THREAD_ARG(thread); smtp_checker_t *smtp_checker = CHECKER_ARG(checker); smtp_host_t *smtp_host; enum connect_result status; int sd; /* Let's review our data structures. * * Thread is the structure used by the sceduler * for sceduling many types of events. thread->arg in this * case points to a checker structure. The checker * structure holds data about the vs and rs configurations * as well as the delay loop, etc. Each real server * defined in the keepalived.conf will more than likely have * a checker structure assigned to it. Each checker structure * has a data element that is meant to hold per checker * configurations. So thread->arg(checker)->data points to * a smtp_checker structure. In the smtp_checker structure * we hold global configuration data for the smtp check. * Smtp_checker has a list of per host (smtp_host) configuration * data in smtp_checker->host. * * So this whole thing looks like this: * thread->arg(checker)->data(smtp_checker)->host(smtp_host) * * To make life simple, we'll break the structures out so * that "checker" always points to the current checker structure, * "smtp_checker" points to the current smtp_checker structure, * and "smtp_host" points to the current smtp_host structure. */ /* * If we're disabled, we'll do nothing at all. * But we still have to register ourselves again so * we don't fall of the face of the earth. */ if (!CHECKER_ENABLED(checker)) { thread_add_timer(thread->master, smtp_connect_thread, checker, checker->vs->delay_loop); return 0; } /* * Set the internal host pointer to the host that well be * working on. If it's NULL, we've successfully tested all hosts. * We'll bring the service up (if it's not already), reset the host list, * and insert the delay loop. When we get scheduled again the host list * will be reset and we will continue on checking them one by one. */ if ((smtp_checker->host_ptr = list_element(smtp_checker->host, smtp_checker->host_ctr)) == NULL) { if (!svr_checker_up(checker->id, checker->rs)) { log_message(LOG_INFO, "Remote SMTP server %s succeed on service." , FMT_CHK(checker)); smtp_alert(checker->rs, NULL, NULL, "UP", "=> CHECK succeed on service <="); update_svr_checker_state(UP, checker->id, checker->vs, checker->rs); } smtp_checker->attempts = 0; smtp_checker->host_ctr = 0; smtp_checker->host_ptr = list_element(smtp_checker->host, 0); thread_add_timer(thread->master, smtp_connect_thread, checker, checker->vs->delay_loop); return 0; } smtp_host = smtp_checker->host_ptr; /* Create the socket, failling here should be an oddity */ if ((sd = socket(smtp_host->dst.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { log_message(LOG_INFO, "SMTP_CHECK connection failed to create socket. Rescheduling."); thread_add_timer(thread->master, smtp_connect_thread, checker, checker->vs->delay_loop); return 0; } status = tcp_bind_connect(sd, smtp_host); /* handle tcp connection status & register callback the next setp in the process */ if(tcp_connection_state(sd, status, thread, smtp_check_thread, smtp_host->connection_to)) { close(sd); log_message(LOG_INFO, "SMTP_CHECK socket bind failed. Rescheduling."); thread_add_timer(thread->master, smtp_connect_thread, checker, checker->vs->delay_loop); } return 0; } keepalived-1.2.13/keepalived/check/ipvswrapper.c0000644000175000017500000006123712334072037021451 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: IPVS Kernel wrapper. Use setsockopt call to add/remove * server to/from the loadbalanced server pool. * * Author: Alexandre Cassen, * * 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. * * 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. * * Copyright (C) 2001-2012 Alexandre Cassen, */ #include "ipvswrapper.h" #include "check_data.h" #include "list.h" #include "utils.h" #include "memory.h" #include "logger.h" /* local helpers functions */ static int parse_timeout(char *, unsigned *); static int string_to_number(const char *, int, int); static int modprobe_ipvs(void); /* fetch virtual server group from group name */ virtual_server_group_t * ipvs_get_group_by_name(char *gname, list l) { element e; virtual_server_group_t *vsg; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg = ELEMENT_DATA(e); if (!strcmp(vsg->gname, gname)) return vsg; } return NULL; } #ifdef _KRNL_2_4_ /* KERNEL 2.4 IPVS handling */ /* Global module def IPVS rules */ static struct ip_vs_rule_user *urule; /* Initialization helpers */ int ipvs_start(void) { log_message(LOG_DEBUG, "Initializing ipvs 2.4"); /* Init IPVS kernel channel */ if (ipvs_init()) { /* try to insmod the ip_vs module if ipvs_init failed */ if (modprobe_ipvs() || ipvs_init()) { log_message(LOG_INFO, "IPVS : Can't initialize ipvs: %s", ipvs_strerror(errno)); return IPVS_ERROR; } } /* Allocate global user rules */ urule = (struct ip_vs_rule_user *) MALLOC(sizeof (struct ip_vs_rule_user)); return IPVS_SUCCESS; } void ipvs_stop(void) { /* Clean up the room */ FREE(urule); ipvs_close(); } static int ipvs_talk(int cmd) { int result; if (result = ipvs_command(cmd, urule)) if ((cmd == IP_VS_SO_SET_EDITDEST) && (errno == ENOENT)) result = ipvs_command(IP_VS_SO_SET_ADDDEST, urule); if (result) log_message(LOG_INFO, "IPVS : %s", ipvs_strerror(errno)); return IPVS_SUCCESS; } int ipvs_syncd_cmd(int cmd, char *ifname, int state, int syncid) { #ifdef _HAVE_IPVS_SYNCD_ memset(urule, 0, sizeof (struct ip_vs_rule_user)); /* prepare user rule */ urule->state = state; urule->syncid = syncid; if (ifname != NULL) strncpy(urule->mcast_ifn, ifname, IP_VS_IFNAME_MAXLEN); /* Talk to the IPVS channel */ return ipvs_talk(cmd); #else log_message(LOG_INFO, "IPVS : Sync daemon not supported"); return IPVS_ERROR; #endif } /* IPVS group range rule */ static int ipvs_group_range_cmd(int cmd, virtual_server_group_entry_t *vsg_entry) { uint32_t addr_ip; int err = 0; /* Parse the whole range */ for (addr_ip = inet_sockaddrip4(&vsg_entry->addr); ((addr_ip >> 24) & 0xFF) <= vsg_entry->range; addr_ip += 0x01000000) { urule->vaddr = addr_ip; urule->vport = inet_sockaddrport(&vsg_entry->addr); /* Talk to the IPVS channel */ err = ipvs_talk(cmd); } return err; } /* set IPVS group rules */ static int ipvs_group_cmd(int cmd, list vs_group, real_server_t * rs, char * vsgname) { virtual_server_group_t *vsg = ipvs_get_group_by_name(vsgname, vs_group); virtual_server_group_entry_t *vsg_entry; list l; element e; int err = 1; /* return if jointure fails */ if (!vsg) return -1; /* visit addr_ip list */ l = vsg->addr_ip; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); urule->vaddr = inet_sockaddrip4(&vsg_entry->addr); urule->vport = inet_sockaddrport(&vsg_entry->addr); /* Talk to the IPVS channel */ if (IPVS_ALIVE(cmd, vsg_entry, rs)) { err = ipvs_talk(cmd); IPVS_SET_ALIVE(cmd, vsg_entry); } } /* visit vfwmark list */ l = vsg->vfwmark; urule->vaddr = 0; urule->vport = 0; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); urule->vfwmark = vsg_entry->vfwmark; /* Talk to the IPVS channel */ if (IPVS_ALIVE(cmd, vsg_entry, rs)) { err = ipvs_talk(cmd); IPVS_SET_ALIVE(cmd, vsg_entry); } } /* visit range list */ l = vsg->range; urule->vfwmark = 0; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); /* Talk to the IPVS channel */ if (IPVS_ALIVE(cmd, vsg_entry, rs)) { err = ipvs_group_range_cmd(cmd, vsg_entry); IPVS_SET_ALIVE(cmd, vsg_entry); } } return err; } /* Fill IPVS rule with root vs infos */ void ipvs_set_rule(int cmd, virtual_server_t * vs, real_server_t * rs) { /* Clean up target rule */ memset(urule, 0, sizeof (struct ip_vs_rule_user)); strncpy(urule->sched_name, vs->sched, IP_VS_SCHEDNAME_MAXLEN); urule->weight = 1; urule->conn_flags = vs->loadbalancing_kind; urule->netmask = ((u_int32_t) 0xffffffff); urule->protocol = vs->service_type; if (!parse_timeout(vs->timeout_persistence, &urule->timeout)) log_message(LOG_INFO, "IPVS : Virtual service %s illegal timeout." , FMT_VS(vs)); if (urule->timeout != 0 || vs->granularity_persistence) urule->vs_flags = IP_VS_SVC_F_PERSISTENT; if (cmd == IP_VS_SO_SET_ADD || cmd == IP_VS_SO_SET_DEL) if (vs->granularity_persistence) urule->netmask = vs->granularity_persistence; /* SVR specific */ if (rs) { if (cmd == IP_VS_SO_SET_ADDDEST || cmd == IP_VS_SO_SET_DELDEST || cmd == IP_VS_SO_SET_EDITDEST) { urule->weight = rs->weight; urule->daddr = inet_sockaddrip4(&rs->addr); urule->dport = inet_sockaddrport(&rs->addr); } } } /* Set/Remove a RS from a VS */ int ipvs_cmd(int cmd, list vs_group, virtual_server_t * vs, real_server_t * rs) { int err = 0; /* Prepare target rule */ ipvs_set_rule(cmd, vs, rs); /* Does the service use inhibit flag ? */ if (cmd == IP_VS_SO_SET_DELDEST && rs->inhibit) { urule->weight = 0; cmd = IP_VS_SO_SET_EDITDEST; } if (cmd == IP_VS_SO_SET_ADDDEST && rs->inhibit && rs->set) cmd = IP_VS_SO_SET_EDITDEST; /* Set flag */ if (cmd == IP_VS_SO_SET_ADDDEST && !rs->set) rs->set = 1; if (cmd == IP_VS_SO_SET_DELDEST && rs->set) rs->set = 0; /* Set vs rule and send to kernel */ if (vs->vsgname) { err = ipvs_group_cmd(cmd, vs_group, rs, vs->vsgname); } else { if (vs->vfwmark) { urule->vfwmark = vs->vfwmark; } else { urule->vaddr = inet_sockaddrip4(&vs->addr); urule->vport = inet_sockaddrport(&vs->addr); } /* Talk to the IPVS channel */ err = ipvs_talk(cmd); } return err; } /* Remove a specific vs group entry */ int ipvs_group_remove_entry(virtual_server_t *vs, virtual_server_group_entry_t *vsge) { real_server_t *rs; int err = 0; element e; list l = vs->rs; /* Clean target rules */ memset(urule, 0, sizeof (struct ip_vs_rule_user)); /* Process realserver queue */ for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { rs = ELEMENT_DATA(e); if (rs->alive) { /* Prepare the IPVS rule */ if (urule->daddr) { /* Setting IPVS rule with vs root rs */ ipvs_set_rule(IP_VS_SO_SET_DELDEST, vs, rs); } else { urule->weight = rs->weight; urule->daddr = inet_sockaddrip4(&rs->addr); urule->dport = inet_sockaddrport(&rs->addr); } /* Set vs rule */ if (vsge->range) { ipvs_group_range_cmd(IP_VS_SO_SET_DELDEST, vsge); } else { urule->vfwmark = vsge->vfwmark; urule->vaddr = inet_sockaddrip4(&vsge->addr); urule->vport = inet_sockaddrport(&vsge->addr); /* Talk to the IPVS channel */ err = ipvs_talk(IP_VS_SO_SET_DELDEST); } } } /* Remove VS entry */ if (vsge->range) err = ipvs_group_range_cmd(IP_VS_SO_SET_DEL, vsge); else err = ipvs_talk(IP_VS_SO_SET_DEL); return err; } #else /* KERNEL 2.6 IPVS handling */ /* Global module def IPVS rules */ static ipvs_service_t *srule; static ipvs_dest_t *drule; static ipvs_daemon_t *daemonrule; /* Initialization helpers */ int ipvs_start(void) { log_message(LOG_DEBUG, "Initializing ipvs 2.6"); /* Initialize IPVS module */ if (ipvs_init()) { if (modprobe_ipvs() || ipvs_init()) { log_message(LOG_INFO, "IPVS: Can't initialize ipvs: %s", ipvs_strerror(errno)); return IPVS_ERROR; } } /* Allocate global user rules */ srule = (ipvs_service_t *) MALLOC(sizeof(ipvs_service_t)); drule = (ipvs_dest_t *) MALLOC(sizeof(ipvs_dest_t)); daemonrule = (ipvs_daemon_t *) MALLOC(sizeof(ipvs_daemon_t)); return IPVS_SUCCESS; } void ipvs_stop(void) { /* Clean up the room */ FREE(srule); FREE(drule); FREE(daemonrule); ipvs_close(); } /* Send user rules to IPVS module */ static void ipvs_talk(int cmd) { int result = -1; switch (cmd) { case IP_VS_SO_SET_STARTDAEMON: result = ipvs_start_daemon(daemonrule); break; case IP_VS_SO_SET_STOPDAEMON: result = ipvs_stop_daemon(daemonrule); break; case IP_VS_SO_SET_ADD: result = ipvs_add_service(srule); break; case IP_VS_SO_SET_DEL: result = ipvs_del_service(srule); break; case IP_VS_SO_SET_EDIT: result = ipvs_update_service(srule); break; case IP_VS_SO_SET_ZERO: result = ipvs_zero_service(srule); break; case IP_VS_SO_SET_ADDDEST: result = ipvs_add_dest(srule, drule); break; case IP_VS_SO_SET_DELDEST: result = ipvs_del_dest(srule, drule); break; case IP_VS_SO_SET_EDITDEST: if ((result = ipvs_update_dest(srule, drule)) && (errno == ENOENT)) result = ipvs_add_dest(srule, drule); break; } if (result) log_message(LOG_INFO, "IPVS: %s", ipvs_strerror(errno)); } int ipvs_syncd_cmd(int cmd, char *ifname, int state, int syncid) { memset(daemonrule, 0, sizeof(ipvs_daemon_t)); /* prepare user rule */ daemonrule->state = state; daemonrule->syncid = syncid; if (ifname != NULL) strncpy(daemonrule->mcast_ifn, ifname, IP_VS_IFNAME_MAXLEN); /* Talk to the IPVS channel */ ipvs_talk(cmd); return IPVS_SUCCESS; } /* IPVS group range rule */ static void ipvs_group_range_cmd(int cmd, virtual_server_group_entry_t *vsg_entry) { uint32_t addr_ip, ip; if (vsg_entry->addr.ss_family == AF_INET6) { inet_sockaddrip6(&vsg_entry->addr, &srule->addr.in6); ip = srule->addr.in6.s6_addr32[3]; } else { ip = inet_sockaddrip4(&vsg_entry->addr); } /* Set Address Family */ srule->af = vsg_entry->addr.ss_family; /* Parse the whole range */ for (addr_ip = ip; ((addr_ip >> 24) & 0xFF) <= vsg_entry->range; addr_ip += 0x01000000) { if (srule->af == AF_INET6) { if (srule->netmask == 0xffffffff) srule->netmask = 128; srule->addr.in6.s6_addr32[3] = addr_ip; } else { srule->addr.ip = addr_ip; } srule->port = inet_sockaddrport(&vsg_entry->addr); /* Talk to the IPVS channel */ ipvs_talk(cmd); } } /* set IPVS group rules */ static void ipvs_group_cmd(int cmd, list vs_group, real_server_t * rs, virtual_server_t * vs) { virtual_server_group_t *vsg = ipvs_get_group_by_name(vs->vsgname, vs_group); virtual_server_group_entry_t *vsg_entry; list l; element e; /* return if jointure fails */ if (!vsg) return; /* visit addr_ip list */ l = vsg->addr_ip; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); srule->af = vsg_entry->addr.ss_family; if (vsg_entry->addr.ss_family == AF_INET6) { if (srule->netmask == 0xffffffff) srule->netmask = 128; inet_sockaddrip6(&vsg_entry->addr, &srule->addr.in6); } else srule->addr.ip = inet_sockaddrip4(&vsg_entry->addr); srule->port = inet_sockaddrport(&vsg_entry->addr); /* Talk to the IPVS channel */ if (IPVS_ALIVE(cmd, vsg_entry, rs)) { ipvs_talk(cmd); IPVS_SET_ALIVE(cmd, vsg_entry); } } /* visit vfwmark list */ l = vsg->vfwmark; srule->addr.ip = 0; srule->af = 0; srule->port = 0; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); srule->af = AF_INET; /* Need to get address family from first real server */ if (vs->rs && !LIST_ISEMPTY(vs->rs) && (((real_server_t *)ELEMENT_DATA(LIST_HEAD(vs->rs)))->addr.ss_family == AF_INET6)) { srule->af = AF_INET6; srule->netmask = 128; } srule->fwmark = vsg_entry->vfwmark; /* Talk to the IPVS channel */ if (IPVS_ALIVE(cmd, vsg_entry, rs)) { ipvs_talk(cmd); IPVS_SET_ALIVE(cmd, vsg_entry); } } /* visit range list */ l = vsg->range; srule->fwmark = 0; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); /* Talk to the IPVS channel */ if (IPVS_ALIVE(cmd, vsg_entry, rs)) { ipvs_group_range_cmd(cmd, vsg_entry); IPVS_SET_ALIVE(cmd, vsg_entry); } } } /* Fill IPVS rule with root vs infos */ void ipvs_set_rule(int cmd, virtual_server_t * vs, real_server_t * rs) { /* Clean target rule */ memset(drule, 0, sizeof(ipvs_dest_t)); drule->weight = 1; drule->u_threshold = 0; drule->l_threshold = 0; drule->conn_flags = vs->loadbalancing_kind; strncpy(srule->sched_name, vs->sched, IP_VS_SCHEDNAME_MAXLEN); srule->netmask = (vs->addr.ss_family == AF_INET6) ? 128 : ((u_int32_t) 0xffffffff); srule->protocol = vs->service_type; if (!parse_timeout(vs->timeout_persistence, &srule->timeout)) log_message(LOG_INFO, "IPVS : Virtual service %s illegal timeout." , FMT_VS(vs)); if (srule->timeout != 0 || vs->granularity_persistence) srule->flags |= IP_VS_SVC_F_PERSISTENT; /* Only for UDP services */ if (vs->ops == 1 && srule->protocol == IPPROTO_UDP) srule->flags |= IP_VS_SVC_F_ONEPACKET; if (cmd == IP_VS_SO_SET_ADD || cmd == IP_VS_SO_SET_DEL) if (vs->granularity_persistence) srule->netmask = vs->granularity_persistence; /* SVR specific */ if (rs) { if (cmd == IP_VS_SO_SET_ADDDEST || cmd == IP_VS_SO_SET_DELDEST || cmd == IP_VS_SO_SET_EDITDEST) { drule->af = rs->addr.ss_family; if (rs->addr.ss_family == AF_INET6) inet_sockaddrip6(&rs->addr, &drule->addr.in6); else drule->addr.ip = inet_sockaddrip4(&rs->addr); drule->port = inet_sockaddrport(&rs->addr); drule->weight = rs->weight; drule->u_threshold = rs->u_threshold; drule->l_threshold = rs->l_threshold; } } } /* Set/Remove a RS from a VS */ int ipvs_cmd(int cmd, list vs_group, virtual_server_t * vs, real_server_t * rs) { /* Allocate the room */ memset(srule, 0, sizeof(ipvs_service_t)); ipvs_set_rule(cmd, vs, rs); /* Does the service use inhibit flag ? */ if (cmd == IP_VS_SO_SET_DELDEST && rs->inhibit) { drule->weight = 0; cmd = IP_VS_SO_SET_EDITDEST; } if (cmd == IP_VS_SO_SET_ADDDEST && rs->inhibit && rs->set) cmd = IP_VS_SO_SET_EDITDEST; /* Set flag */ if (cmd == IP_VS_SO_SET_ADDDEST && !rs->set) rs->set = 1; if (cmd == IP_VS_SO_SET_DELDEST && rs->set) rs->set = 0; /* Set vs rule and send to kernel */ if (vs->vsgname) { ipvs_group_cmd(cmd, vs_group, rs, vs); } else { if (vs->vfwmark) { srule->af = AF_INET; /* Need to get address family from first real server */ if (vs->rs && !LIST_ISEMPTY(vs->rs) && (((real_server_t *)ELEMENT_DATA(LIST_HEAD(vs->rs)))->addr.ss_family == AF_INET6)) { srule->af = AF_INET6; srule->netmask = 128; } srule->fwmark = vs->vfwmark; } else { srule->af = vs->addr.ss_family; if (vs->addr.ss_family == AF_INET6) inet_sockaddrip6(&vs->addr, &srule->addr.in6); else srule->addr.ip = inet_sockaddrip4(&vs->addr); srule->port = inet_sockaddrport(&vs->addr); } /* Talk to the IPVS channel */ ipvs_talk(cmd); } return IPVS_SUCCESS; } /* Remove a specific vs group entry */ int ipvs_group_remove_entry(virtual_server_t *vs, virtual_server_group_entry_t *vsge) { real_server_t *rs; element e; list l = vs->rs; /* Clean target rules */ memset(srule, 0, sizeof(ipvs_service_t)); memset(drule, 0, sizeof(ipvs_dest_t)); /* Process realserver queue */ for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { rs = ELEMENT_DATA(e); if (rs->alive) { /* Prepare the IPVS rule */ if (!drule->addr.ip) { /* Setting IPVS rule with vs root rs */ ipvs_set_rule(IP_VS_SO_SET_DELDEST, vs, rs); } else { drule->af = rs->addr.ss_family; if (rs->addr.ss_family == AF_INET6) inet_sockaddrip6(&rs->addr, &drule->addr.in6); else drule->addr.ip = inet_sockaddrip4(&rs->addr); drule->port = inet_sockaddrport(&rs->addr); drule->weight = rs->weight; } /* Set vs rule */ if (vsge->range) { ipvs_group_range_cmd(IP_VS_SO_SET_DELDEST, vsge); } else { srule->af = vsge->addr.ss_family; if (vsge->addr.ss_family == AF_INET6) inet_sockaddrip6(&vsge->addr, &srule->addr.in6); else srule->addr.ip = inet_sockaddrip4(&vsge->addr); srule->port = inet_sockaddrport(&vsge->addr); srule->fwmark = vsge->vfwmark; drule->u_threshold = rs->u_threshold; drule->l_threshold = rs->l_threshold; /* Talk to the IPVS channel */ ipvs_talk(IP_VS_SO_SET_DELDEST); } } } /* Remove VS entry */ if (vsge->range) ipvs_group_range_cmd(IP_VS_SO_SET_DEL, vsge); else ipvs_talk(IP_VS_SO_SET_DEL); return IPVS_SUCCESS; } #ifdef _WITH_SNMP_ /* Update statistics for a given virtual server. This includes statistics of real servers. The update is only done if we need refreshing. */ void ipvs_update_stats(virtual_server_t *vs) { element e, ge = NULL; real_server_t *rs; virtual_server_group_t *vsg = NULL; virtual_server_group_entry_t *vsg_entry = NULL; uint32_t addr_ip = 0; union nf_inet_addr nfaddr; ipvs_service_entry_t * serv = NULL; struct ip_vs_get_dests * dests = NULL; int i; #define UPDATE_STATS_INIT 1 #define UPDATE_STATS_VSG_IP 2 #define UPDATE_STATS_VSG_FWMARK 4 #define UPDATE_STATS_VSG_RANGE 6 #define UPDATE_STATS_VSG_RANGE_IP 7 #define UPDATE_STATS_END 99 int state = UPDATE_STATS_INIT; if (time(NULL) - vs->lastupdated < STATS_REFRESH) return; vs->lastupdated = time(NULL); /* Reset stats */ memset(&vs->stats, 0, sizeof(vs->stats)); if (vs->s_svr) { memset(&vs->s_svr->stats, 0, sizeof(vs->s_svr->stats)); vs->s_svr->activeconns = vs->s_svr->inactconns = vs->s_svr->persistconns = 0; } if (!LIST_ISEMPTY(vs->rs)) { for (e = LIST_HEAD(vs->rs); e; ELEMENT_NEXT(e)) { rs = ELEMENT_DATA(e); memset(&rs->stats, 0, sizeof(rs->stats)); rs->activeconns = rs->inactconns = rs->persistconns = 0; } } /* FSM: at each transition, we process "serv" if it is not NULL */ while (state != UPDATE_STATS_END) { serv = NULL; switch (state) { case UPDATE_STATS_INIT: /* We need to know the next state to reach */ if (vs->vsgname) { if (!LIST_ISEMPTY(check_data->vs_group)) vsg = ipvs_get_group_by_name(vs->vsgname, check_data->vs_group); else vsg = NULL; if (!vsg) state = UPDATE_STATS_END; else { state = UPDATE_STATS_VSG_IP; ge = NULL; } continue; } state = UPDATE_STATS_END; if (vs->vfwmark) { memset(&nfaddr, 0, sizeof(nfaddr)); serv = ipvs_get_service(vs->vfwmark, AF_INET, vs->service_type, nfaddr, 0); break; } memcpy(&nfaddr, (vs->addr.ss_family == AF_INET6)? (void*)(&((struct sockaddr_in6 *)&vs->addr)->sin6_addr): (void*)(&((struct sockaddr_in *)&vs->addr)->sin_addr), sizeof(nfaddr)); serv = ipvs_get_service(0, vs->addr.ss_family, vs->service_type, nfaddr, inet_sockaddrport(&vs->addr)); break; case UPDATE_STATS_VSG_IP: if (!ge) ge = LIST_HEAD(vsg->addr_ip); else ELEMENT_NEXT(ge); if (!ge) { state = UPDATE_STATS_VSG_FWMARK; continue; } vsg_entry = ELEMENT_DATA(ge); memcpy(&nfaddr, (vsg_entry->addr.ss_family == AF_INET6)? (void*)(&((struct sockaddr_in6 *)&vsg_entry->addr)->sin6_addr): (void*)(&((struct sockaddr_in *)&vsg_entry->addr)->sin_addr), sizeof(nfaddr)); serv = ipvs_get_service(0, vsg_entry->addr.ss_family, vs->service_type, nfaddr, inet_sockaddrport(&vsg_entry->addr)); break; case UPDATE_STATS_VSG_FWMARK: if (!ge) ge = LIST_HEAD(vsg->vfwmark); else ELEMENT_NEXT(ge); if (!ge) { state = UPDATE_STATS_VSG_RANGE; continue; } vsg_entry = ELEMENT_DATA(ge); memset(&nfaddr, 0, sizeof(nfaddr)); serv = ipvs_get_service(vsg_entry->vfwmark, AF_INET, vs->service_type, nfaddr, 0); break; case UPDATE_STATS_VSG_RANGE: if (!ge) ge = LIST_HEAD(vsg->range); else ELEMENT_NEXT(ge); if (!ge) { state = UPDATE_STATS_END; continue; } vsg_entry = ELEMENT_DATA(ge); addr_ip = (vsg_entry->addr.ss_family == AF_INET6) ? ((struct sockaddr_in6 *)&vsg_entry->addr)->sin6_addr.s6_addr32[3]: ((struct sockaddr_in *)&vsg_entry->addr)->sin_addr.s_addr; state = UPDATE_STATS_VSG_RANGE_IP; continue; case UPDATE_STATS_VSG_RANGE_IP: if (((addr_ip >> 24) & 0xFF) > vsg_entry->range) { state = UPDATE_STATS_VSG_RANGE; continue; } if (vsg_entry->addr.ss_family == AF_INET6) { inet_sockaddrip6(&vsg_entry->addr, &nfaddr.in6); nfaddr.in6.s6_addr32[3] = addr_ip; } else { nfaddr.in.s_addr = addr_ip; } serv = ipvs_get_service(0, vsg_entry->addr.ss_family, vs->service_type, nfaddr, inet_sockaddrport(&vsg_entry->addr)); addr_ip += 0x01000000; break; } if (!serv) continue; /* Update virtual server stats */ #define ADD_TO_VSSTATS(X) vs->stats.X += serv->stats.X; ADD_TO_VSSTATS(conns); ADD_TO_VSSTATS(inpkts); ADD_TO_VSSTATS(outpkts); ADD_TO_VSSTATS(inbytes); ADD_TO_VSSTATS(outbytes); ADD_TO_VSSTATS(cps); ADD_TO_VSSTATS(inpps); ADD_TO_VSSTATS(outpps); ADD_TO_VSSTATS(inbps); ADD_TO_VSSTATS(outbps); /* Get real servers */ dests = ipvs_get_dests(serv); if (!dests) { FREE(serv); return; } for (i = 0; i < dests->num_dests; i++) { rs = NULL; #define VSD_EQUAL(entity) (((entity)->addr.ss_family == AF_INET && \ dests->entrytable[i].af == AF_INET && \ inaddr_equal(AF_INET, \ &dests->entrytable[i].addr, \ &((struct sockaddr_in *)&(entity)->addr)->sin_addr) && \ dests->entrytable[i].port == ((struct sockaddr_in *)&(entity)->addr)->sin_port) || \ ((entity)->addr.ss_family == AF_INET6 && \ dests->entrytable[i].af == AF_INET6 && \ inaddr_equal(AF_INET6, \ &dests->entrytable[i].addr, \ &((struct sockaddr_in6 *)&(entity)->addr)->sin6_addr) && \ dests->entrytable[i].port == ((struct sockaddr_in6 *)&(entity)->addr)->sin6_port)) /* Is it the sorry server? */ if (vs->s_svr && VSD_EQUAL(vs->s_svr)) rs = vs->s_svr; else if (!LIST_ISEMPTY(vs->rs)) /* Search for a match in the list of real servers */ for (e = LIST_HEAD(vs->rs); e; ELEMENT_NEXT(e)) { rs = ELEMENT_DATA(e); if (VSD_EQUAL(rs)) break; } if (rs) { #define ADD_TO_RSSTATS(X) rs->X += dests->entrytable[i].X ADD_TO_RSSTATS(activeconns); ADD_TO_RSSTATS(inactconns); ADD_TO_RSSTATS(persistconns); ADD_TO_RSSTATS(stats.conns); ADD_TO_RSSTATS(stats.inpkts); ADD_TO_RSSTATS(stats.outpkts); ADD_TO_RSSTATS(stats.inbytes); ADD_TO_RSSTATS(stats.outbytes); ADD_TO_RSSTATS(stats.cps); ADD_TO_RSSTATS(stats.inpps); ADD_TO_RSSTATS(stats.outpps); ADD_TO_RSSTATS(stats.inbps); ADD_TO_RSSTATS(stats.outbps); } } FREE(dests); FREE(serv); } } #endif /* _WITH_SNMP_ */ #endif /* * Common IPVS functions */ void ipvs_syncd_master(char *ifname, int syncid) { ipvs_syncd_cmd(IPVS_STOPDAEMON, ifname, IPVS_BACKUP, syncid); ipvs_syncd_cmd(IPVS_STARTDAEMON, ifname, IPVS_MASTER, syncid); } void ipvs_syncd_backup(char *ifname, int syncid) { ipvs_syncd_cmd(IPVS_STOPDAEMON, ifname, IPVS_MASTER, syncid); ipvs_syncd_cmd(IPVS_STARTDAEMON, ifname, IPVS_BACKUP, syncid); } /* * Utility functions coming from Wensong code */ static int parse_timeout(char *buf, unsigned *timeout) { int i; if (buf == NULL) { *timeout = IP_VS_TEMPLATE_TIMEOUT; return 1; } if ((i = string_to_number(buf, 0, 86400 * 31)) == -1) return 0; *timeout = i * (IP_VS_TEMPLATE_TIMEOUT / (6*60)); return 1; } static int string_to_number(const char *s, int min, int max) { int number; char *end; number = (int) strtol(s, &end, 10); if (*end == '\0' && end != s) { /* * We parsed a number, let's see if we want this. * If max <= min then ignore ranges */ if (max <= min || (min <= number && number <= max)) return number; else return -1; } else return -1; } static int modprobe_ipvs(void) { char *argv[] = { "/sbin/modprobe", "-s", "--", "ip_vs", NULL }; int child; int status; int rc; if (!(child = fork())) { execv(argv[0], argv); exit(1); } rc = waitpid(child, &status, 0); if (rc < 0) { log_message(LOG_INFO, "IPVS: waitpid error (%s)" , strerror(errno)); } if (!WIFEXITED(status) || WEXITSTATUS(status)) { return 1; } return 0; } keepalived-1.2.13/README0000664000175000017500000000175712211121152014403 0ustar acassenacassenThe main goal of the keepalived project is to add a strong & robust keepalive facility to the Linux Virtual Server project. It implements a multilayer TCP/IP stack checks. Keepalived implements a framework based on three family checks : Layer3, Layer4 & Layer5. This framework gives the daemon the ability of checking a LVS server pool states. Keepalived can be sumarize as a LVS driving daemon. Keepalived implementation is based on an I/O multiplexer to handle a strong multi-threading framework. All the events process use this I/O multiplexer. Keepalived is free software, Copyright (C) Alexandre Cassen. See the file COPYING for copying conditions. OPENSSL TOOLKIT LICENCE EXCEPTION In addition, as the copyright holder of Keepalived, I, Alexandre Cassen, , grant the following special exception: I, Alexandre Cassen, , explicitly allow the compilation and distribution of the Keepalived software with the OpenSSL Toolkit. keepalived-1.2.13/configure0000755000175000017500000052054212334072037015443 0ustar acassenacassen#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="keepalived/core/main.c" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS VRRP_SUPPORT USE_NL IPVS_SUPPORT VERSION_DATE VERSION DFLAGS SO_MARK_SUPPORT SHA1_SUPPORT SNMP_SUPPORT NETSNMP_CONFIG VRRP_VMAC IPVS_SYNCD KERN EGREP GREP CPP STRIP INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_lvs_syncd enable_lvs enable_vrrp with_kernel_dir with_kernel_version enable_fwmark enable_snmp enable_sha1 enable_debug enable_profile ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-lvs-syncd do not use LVS synchronization daemon --disable-lvs do not use the LVS framework --disable-vrrp do not use the VRRP framework --disable-fwmark compile without SO_MARK support --enable-snmp compile with SNMP support --enable-sha1 compile with SHA1 support --enable-debug compile with debugging flags --enable-profile compile with profiling flags Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-kernel-dir=DIR path to linux kernel source directory --with-kernel-version=VER forced value for linux kernel version (VER=2.4|2.6) Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES # --------------------------------------------- # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. ac_fn_c_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 $as_echo_n "checking whether $as_decl_name is declared... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_decl # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu VERSION=`cat VERSION` VERSION_DATE=`date +%m/%d,20%y` OUTPUT_TARGET="Makefile genhash/Makefile keepalived/core/Makefile lib/config.h keepalived.spec" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi # Check whether --enable-lvs-syncd was given. if test "${enable_lvs_syncd+set}" = set; then : enableval=$enable_lvs_syncd; fi # Check whether --enable-lvs was given. if test "${enable_lvs+set}" = set; then : enableval=$enable_lvs; fi # Check whether --enable-vrrp was given. if test "${enable_vrrp+set}" = set; then : enableval=$enable_vrrp; fi # Check whether --with-kernel-dir was given. if test "${with_kernel_dir+set}" = set; then : withval=$with_kernel_dir; kernelinc="$withval/include" kernelpath="$withval" else kernelinc="/usr/src/linux/include" kernelpath="/usr/src/linux" fi # Check whether --with-kernel-version was given. if test "${with_kernel_version+set}" = set; then : withval=$with_kernel_version; kernelversion="$withval" else kernelversion="" fi # Check whether --enable-fwmark was given. if test "${enable_fwmark+set}" = set; then : enableval=$enable_fwmark; fi # Check whether --enable-snmp was given. if test "${enable_snmp+set}" = set; then : enableval=$enable_snmp; fi # Check whether --enable-sha1 was given. if test "${enable_sha1+set}" = set; then : enableval=$enable_sha1; fi # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; fi # Check whether --enable-profile was given. if test "${enable_profile+set}" = set; then : enableval=$enable_profile; fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if ${ac_cv_header_sys_wait_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main () { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_sys_wait_h=yes else ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 $as_echo "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in fcntl.h syslog.h unistd.h sys/ioctl.h sys/time.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in openssl/ssl.h openssl/md5.h openssl/err.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF else as_fn_error $? " !!! OpenSSL is not properly installed on your system. !!! !!! Can not include OpenSSL headers files. !!!" "$LINENO" 5 fi done ac_fn_c_check_decl "$LINENO" "ETHERTYPE_IPV6" "ac_cv_have_decl_ETHERTYPE_IPV6" "#include " if test "x$ac_cv_have_decl_ETHERTYPE_IPV6" = xyes; then : else CFLAGS="$CFLAGS -DETHERTYPE_IPV6=0x86dd" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5 $as_echo_n "checking for crypt in -lcrypt... " >&6; } if ${ac_cv_lib_crypt_crypt+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char crypt (); int main () { return crypt (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_crypt_crypt=yes else ac_cv_lib_crypt_crypt=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5 $as_echo "$ac_cv_lib_crypt_crypt" >&6; } if test "x$ac_cv_lib_crypt_crypt" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBCRYPT 1 _ACEOF LIBS="-lcrypt $LIBS" else as_fn_error $? "crypt() function is required" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MD5_Init in -lcrypto" >&5 $as_echo_n "checking for MD5_Init in -lcrypto... " >&6; } if ${ac_cv_lib_crypto_MD5_Init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypto $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char MD5_Init (); int main () { return MD5_Init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_crypto_MD5_Init=yes else ac_cv_lib_crypto_MD5_Init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_MD5_Init" >&5 $as_echo "$ac_cv_lib_crypto_MD5_Init" >&6; } if test "x$ac_cv_lib_crypto_MD5_Init" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBCRYPTO 1 _ACEOF LIBS="-lcrypto $LIBS" else as_fn_error $? "OpenSSL libraries are required" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_CTX_new in -lssl" >&5 $as_echo_n "checking for SSL_CTX_new in -lssl... " >&6; } if ${ac_cv_lib_ssl_SSL_CTX_new+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lssl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char SSL_CTX_new (); int main () { return SSL_CTX_new (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ssl_SSL_CTX_new=yes else ac_cv_lib_ssl_SSL_CTX_new=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_CTX_new" >&5 $as_echo "$ac_cv_lib_ssl_SSL_CTX_new" >&6; } if test "x$ac_cv_lib_ssl_SSL_CTX_new" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSSL 1 _ACEOF LIBS="-lssl $LIBS" else as_fn_error $? "OpenSSL libraries are required" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_socket_alloc in -lnl-3" >&5 $as_echo_n "checking for nl_socket_alloc in -lnl-3... " >&6; } if ${ac_cv_lib_nl_3_nl_socket_alloc+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnl-3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char nl_socket_alloc (); int main () { return nl_socket_alloc (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nl_3_nl_socket_alloc=yes else ac_cv_lib_nl_3_nl_socket_alloc=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nl_3_nl_socket_alloc" >&5 $as_echo "$ac_cv_lib_nl_3_nl_socket_alloc" >&6; } if test "x$ac_cv_lib_nl_3_nl_socket_alloc" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for genl_connect in -lnl-genl-3" >&5 $as_echo_n "checking for genl_connect in -lnl-genl-3... " >&6; } if ${ac_cv_lib_nl_genl_3_genl_connect+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnl-genl-3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char genl_connect (); int main () { return genl_connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nl_genl_3_genl_connect=yes else ac_cv_lib_nl_genl_3_genl_connect=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nl_genl_3_genl_connect" >&5 $as_echo "$ac_cv_lib_nl_genl_3_genl_connect" >&6; } if test "x$ac_cv_lib_nl_genl_3_genl_connect" = xyes; then : USE_NL="LIBIPVS_USE_NL" CFLAGS="$CFLAGS $(pkg-config --cflags libnl-genl-3.0)" LIBS="$LIBS $(pkg-config --libs libnl-genl-3.0)" else as_fn_error $? "libnl-3 is installed but not libnl-gen-3. Please, install libnl-gen-3." "$LINENO" 5 fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_socket_modify_cb in -lnl" >&5 $as_echo_n "checking for nl_socket_modify_cb in -lnl... " >&6; } if ${ac_cv_lib_nl_nl_socket_modify_cb+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char nl_socket_modify_cb (); int main () { return nl_socket_modify_cb (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nl_nl_socket_modify_cb=yes else ac_cv_lib_nl_nl_socket_modify_cb=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nl_nl_socket_modify_cb" >&5 $as_echo "$ac_cv_lib_nl_nl_socket_modify_cb" >&6; } if test "x$ac_cv_lib_nl_nl_socket_modify_cb" = xyes; then : USE_NL="LIBIPVS_USE_NL" CFLAGS="$CFLAGS -DFALLBACK_LIBNL1" LIBS="$LIBS $(pkg-config --libs libnl-1)" else USE_NL="LIBIPVS_DONTUSE_NL" { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: keepalived will be built without libnl support." >&5 $as_echo "$as_me: WARNING: keepalived will be built without libnl support." >&2;} fi fi CPPFLAGS="$CPPFLAGS -I$kernelinc" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for kernel version" >&5 $as_echo_n "checking for kernel version... " >&6; } if test "$cross_compiling" = yes; then : LINUX_MAJOR="0" LINUX_MINOR="0" LINUX_PATCH="0" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #if !defined(UTS_RELEASE) && !defined(LINUX_VERSION_CODE) #include #endif int main (void) { FILE *fp = fopen ("linuxinfo", "w"); if (!fp) return 1; #if defined(UTS_RELEASE) fprintf (fp, "%s\n", UTS_RELEASE); #elif defined(LINUX_VERSION_CODE) fprintf (fp, "%d.%d.%d\n", LINUX_VERSION_CODE >> 16, (LINUX_VERSION_CODE >> 8) & 0xFF, LINUX_VERSION_CODE & 0xFF); #else fprintf (fp, "0.0.0\n"); /* Let's fail gently */ #endif fclose (fp); return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : LINUX_MAJOR=`cat linuxinfo | cut -d'.' -f1` LINUX_MINOR=`cat linuxinfo | cut -d'.' -f2` LINUX_PATCH=`cat linuxinfo | cut -d'.' -f3` else LINUX_MAJOR="0" LINUX_MINOR="0" LINUX_PATCH="0" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f linuxinfo if test "$kernelversion" = "2.4"; then KERN="_KRNL_2_4_" { $as_echo "$as_me:${as_lineno-$LINENO}: result: 2.4" >&5 $as_echo "2.4" >&6; } elif test "$kernelversion" = "2.6"; then KERN="_KRNL_2_6_" { $as_echo "$as_me:${as_lineno-$LINENO}: result: 2.6" >&5 $as_echo "2.6" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LINUX_MAJOR.$LINUX_MINOR.$LINUX_PATCH" >&5 $as_echo "$LINUX_MAJOR.$LINUX_MINOR.$LINUX_PATCH" >&6; } if test "$LINUX_MAJOR" = "2" && test "$LINUX_MINOR" = "6"; then KERN="_KRNL_2_6_" elif test "$LINUX_MAJOR" = "2" && test "$LINUX_MINOR" = "4"; then KERN="_KRNL_2_4_" else KERN="_KRNL_2_6_" fi if test "$LINUX_MAJOR" = "0" -a "$LINUX_MINOR" = "0" -a "$LINUX_PATCH" = "0"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Cannot determine Linux Kernel version." >&5 $as_echo "$as_me: WARNING: Cannot determine Linux Kernel version." >&2;} fi fi IPVS_SUPPORT="_WITHOUT_LVS_" if test "$enable_lvs" != "no"; then if test "$KERN" = "_KRNL_2_6_"; then IPVS_SUPPORT="_WITH_LVS_" else ac_fn_c_check_header_mongrel "$LINENO" "net/ip_vs.h" "ac_cv_header_net_ip_vs_h" "$ac_includes_default" if test "x$ac_cv_header_net_ip_vs_h" = xyes; then : IPVS_SUPPORT="_WITH_LVS_" else IPVS_SUPPORT="_WITHOUT_LVS_" { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: keepalived will be built without LVS support." >&5 $as_echo "$as_me: WARNING: keepalived will be built without LVS support." >&2;} fi fi fi if test "$IPVS_SUPPORT" = "_WITHOUT_LVS_" -a "$enable_vrrp" = "no"; then as_fn_error $? "keepalived MUST be compiled at least with LVS or VRRP framework" "$LINENO" 5 fi IPVS_SYNCD="_WITHOUT_IPVS_SYNCD_" if test "$IPVS_SUPPORT" = "_WITH_LVS_"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IPVS syncd support" >&5 $as_echo_n "checking for IPVS syncd support... " >&6; } if test "$KERN" = "_KRNL_2_6_"; then IPVS_SYNCD="_HAVE_IPVS_SYNCD_" elif test "_KRNL_2_4_"; then IPVS_SYNCD="_HAVE_IPVS_SYNCD_" else IPVS_SYNCD="_WITHOUT_IPVS_SYNCD_" fi if test "${IPVS_SUPPORT}" = "_WITHOUT_LVS_" -o "$enable_lvs_syncd" = "no"; then IPVS_SYNCD="_WITHOUT_IPVS_SYNCD_" fi if test "$IPVS_SYNCD" = "_HAVE_IPVS_SYNCD_"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi VRRP_SUPPORT="_WITHOUT_VRRP_" if test "$enable_vrrp" != "no"; then VRRP_SUPPORT="_WITH_VRRP_" fi CPPFLAGS="$CPPFLAGS -I$kernelinc" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for kernel macvlan support" >&5 $as_echo_n "checking for kernel macvlan support... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int macvlan; int main () { macvlan = IFLA_MACVLAN_MODE; macvlan = MACVLAN_MODE_PRIVATE; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : MACVLAN_SUPPORT=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext; if test "$MACVLAN_SUPPORT" = "yes"; then VRRP_VMAC="_HAVE_VRRP_VMAC_" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else VRRP_VMAC="_WITHOUT_VRRP_VMAC_" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi SNMP_SUPPORT="_WITHOUT_SNMP_" if test "$enable_snmp" = "yes"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}net-snmp-config", so it can be a program name with args. set dummy ${ac_tool_prefix}net-snmp-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_NETSNMP_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $NETSNMP_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_NETSNMP_CONFIG="$NETSNMP_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_NETSNMP_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi NETSNMP_CONFIG=$ac_cv_path_NETSNMP_CONFIG if test -n "$NETSNMP_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NETSNMP_CONFIG" >&5 $as_echo "$NETSNMP_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_NETSNMP_CONFIG"; then ac_pt_NETSNMP_CONFIG=$NETSNMP_CONFIG # Extract the first word of "net-snmp-config", so it can be a program name with args. set dummy net-snmp-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_NETSNMP_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_NETSNMP_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_NETSNMP_CONFIG="$ac_pt_NETSNMP_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_NETSNMP_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_NETSNMP_CONFIG=$ac_cv_path_ac_pt_NETSNMP_CONFIG if test -n "$ac_pt_NETSNMP_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_NETSNMP_CONFIG" >&5 $as_echo "$ac_pt_NETSNMP_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_NETSNMP_CONFIG" = x; then NETSNMP_CONFIG="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NETSNMP_CONFIG=$ac_pt_NETSNMP_CONFIG fi else NETSNMP_CONFIG="$ac_cv_path_NETSNMP_CONFIG" fi if test x"$NETSNMP_CONFIG" = x"no"; then as_fn_error $? "unable to find net-snmp-config" "$LINENO" 5 fi NETSNMP_LIBS=`${NETSNMP_CONFIG} --agent-libs` #NETSNMP_CFLAGS="`${NETSNMP_CONFIG} --base-cflags`" #CFLAGS="${NETSNMP_CFLAGS} $CFLAGS" LIBS="${NETSNMP_LIBS} $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler supports flag \"${NETSNMP_LIBS}\" from Net-SNMP" >&5 $as_echo_n "checking whether C compiler supports flag \"${NETSNMP_LIBS}\" from Net-SNMP... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void); int main () { { return 0; } ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "incorrect CFLAGS from net-snmp-config" "$LINENO" 5 fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext # Do we have a usable header? for ac_header in net-snmp/agent/util_funcs.h do : ac_fn_c_check_header_compile "$LINENO" "net-snmp/agent/util_funcs.h" "ac_cv_header_net_snmp_agent_util_funcs_h" " #include #include #include #include #include " if test "x$ac_cv_header_net_snmp_agent_util_funcs_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NET_SNMP_AGENT_UTIL_FUNCS_H 1 _ACEOF fi done SNMP_SUPPORT="_WITH_SNMP_" fi SHA1_SUPPORT="_WITHOUT_SHA1_" if test "${enable_sha1}" = "yes"; then CFLAGS="$CFLAGS -DFEAT_SHA1" for ac_header in openssl/sha.h do : ac_fn_c_check_header_mongrel "$LINENO" "openssl/sha.h" "ac_cv_header_openssl_sha_h" "$ac_includes_default" if test "x$ac_cv_header_openssl_sha_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_OPENSSL_SHA_H 1 _ACEOF else as_fn_error $? "unable to find openssl/sha.h" "$LINENO" 5 fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SHA1_Init in -lcrypto" >&5 $as_echo_n "checking for SHA1_Init in -lcrypto... " >&6; } if ${ac_cv_lib_crypto_SHA1_Init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypto $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char SHA1_Init (); int main () { return SHA1_Init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_crypto_SHA1_Init=yes else ac_cv_lib_crypto_SHA1_Init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_SHA1_Init" >&5 $as_echo "$ac_cv_lib_crypto_SHA1_Init" >&6; } if test "x$ac_cv_lib_crypto_SHA1_Init" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBCRYPTO 1 _ACEOF LIBS="-lcrypto $LIBS" else as_fn_error $? "SHA1 in OpenSSL required" "$LINENO" 5 fi SHA1_SUPPORT="_WITH_SHA1_" fi if test "${enable_fwmark}" = "no"; then SO_MARK_SUPPORT="_WITHOUT_SO_MARK_" else ac_fn_c_check_decl "$LINENO" "SO_MARK" "ac_cv_have_decl_SO_MARK" "#include " if test "x$ac_cv_have_decl_SO_MARK" = xyes; then : else as_fn_error $? "No SO_MARK declaration in headers" "$LINENO" 5 fi SO_MARK_SUPPORT="_WITH_SO_MARK_" fi if test "${enable_debug}" = "yes"; then DFLAGS="-D_DEBUG_" fi if test "${enable_profile}" = "yes"; then CFLAGS="$CFLAGS -pg" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" if test "x$ac_cv_type_pid_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define pid_t int _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } if ${ac_cv_header_time+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main () { if ((struct tm *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_time=yes else ac_cv_header_time=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 $as_echo "$ac_cv_header_time" >&6; } if test $ac_cv_header_time = yes; then $as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h fi if test $ac_cv_c_compiler_gnu = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5 $as_echo_n "checking whether $CC needs -traditional... " >&6; } if ${ac_cv_prog_gcc_traditional+:} false; then : $as_echo_n "(cached) " >&6 else ac_pattern="Autoconf.*'x'" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Autoconf TIOCGETP _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "$ac_pattern" >/dev/null 2>&1; then : ac_cv_prog_gcc_traditional=yes else ac_cv_prog_gcc_traditional=no fi rm -f conftest* if test $ac_cv_prog_gcc_traditional = no; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Autoconf TCGETA _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "$ac_pattern" >/dev/null 2>&1; then : ac_cv_prog_gcc_traditional=yes fi rm -f conftest* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5 $as_echo "$ac_cv_prog_gcc_traditional" >&6; } if test $ac_cv_prog_gcc_traditional = yes; then CC="$CC -traditional" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working memcmp" >&5 $as_echo_n "checking for working memcmp... " >&6; } if ${ac_cv_func_memcmp_working+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_memcmp_working=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Some versions of memcmp are not 8-bit clean. */ char c0 = '\100', c1 = '\200', c2 = '\201'; if (memcmp(&c0, &c2, 1) >= 0 || memcmp(&c1, &c2, 1) >= 0) return 1; /* The Next x86 OpenStep bug shows up only when comparing 16 bytes or more and with at least one buffer not starting on a 4-byte boundary. William Lewis provided this test program. */ { char foo[21]; char bar[21]; int i; for (i = 0; i < 4; i++) { char *a = foo + i; char *b = bar + i; strcpy (a, "--------01111111"); strcpy (b, "--------10000000"); if (memcmp (a, b, 16) >= 0) return 1; } return 0; } ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_memcmp_working=yes else ac_cv_func_memcmp_working=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_memcmp_working" >&5 $as_echo "$ac_cv_func_memcmp_working" >&6; } test $ac_cv_func_memcmp_working = no && case " $LIBOBJS " in *" memcmp.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS memcmp.$ac_objext" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 $as_echo_n "checking return type of signal handlers... " >&6; } if ${ac_cv_type_signal+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { return *(signal (0, 0)) (0) == 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_type_signal=int else ac_cv_type_signal=void fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5 $as_echo "$ac_cv_type_signal" >&6; } cat >>confdefs.h <<_ACEOF #define RETSIGTYPE $ac_cv_type_signal _ACEOF for ac_func in gettimeofday select socket strerror strtol uname do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done OUTPUT_TARGET="$OUTPUT_TARGET keepalived/Makefile lib/Makefile" if test "${VRRP_SUPPORT}" = "_WITH_VRRP_"; then OUTPUT_TARGET="$OUTPUT_TARGET keepalived/vrrp/Makefile" fi if test "$IPVS_SUPPORT" = "_WITH_LVS_"; then OUTPUT_TARGET="$OUTPUT_TARGET keepalived/check/Makefile" if test "$KERN" = "_KRNL_2_6_"; then OUTPUT_TARGET="$OUTPUT_TARGET keepalived/libipvs-2.6/Makefile" elif test "$KERN" = "_KRNL_2_4_"; then OUTPUT_TARGET="$OUTPUT_TARGET keepalived/libipvs-2.4/Makefile" fi fi ac_config_files="$ac_config_files $OUTPUT_TARGET" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "$OUTPUT_TARGET") CONFIG_FILES="$CONFIG_FILES $OUTPUT_TARGET" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi cat < dnl ----[ Process this file with autoconf to produce a configure script ]---- AC_INIT(keepalived/core/main.c) VERSION=`cat VERSION` VERSION_DATE=`date +%m/%d,20%y` OUTPUT_TARGET="Makefile genhash/Makefile keepalived/core/Makefile lib/config.h keepalived.spec" dnl ----[ Checks for programs ]---- AC_PROG_CC AC_PROG_INSTALL AC_CHECK_TOOL(STRIP,strip) dnl ----[ Keepalived specific configure options ]---- AC_ARG_ENABLE(lvs-syncd, [ --disable-lvs-syncd do not use LVS synchronization daemon]) AC_ARG_ENABLE(lvs, [ --disable-lvs do not use the LVS framework]) AC_ARG_ENABLE(vrrp, [ --disable-vrrp do not use the VRRP framework]) AC_ARG_WITH(kernel-dir, [ --with-kernel-dir=DIR path to linux kernel source directory], [kernelinc="$withval/include" kernelpath="$withval"], [kernelinc="/usr/src/linux/include" kernelpath="/usr/src/linux"]) AC_ARG_WITH(kernel-version, [ --with-kernel-version=VER forced value for linux kernel version (VER=2.4|2.6)], [kernelversion="$withval"], [kernelversion=""]) AC_ARG_ENABLE(fwmark, [ --disable-fwmark compile without SO_MARK support]) AC_ARG_ENABLE(snmp, [ --enable-snmp compile with SNMP support]) AC_ARG_ENABLE(sha1, [ --enable-sha1 compile with SHA1 support]) AC_ARG_ENABLE(debug, [ --enable-debug compile with debugging flags]) AC_ARG_ENABLE(profile, [ --enable-profile compile with profiling flags]) dnl ----[ Checks for header files ]---- AC_HEADER_STDC AC_HEADER_SYS_WAIT AC_CHECK_HEADERS(fcntl.h syslog.h unistd.h sys/ioctl.h sys/time.h) dnl [do we really need this ?] AC_CHECK_HEADERS(linux/netlink.h linux/rtnetlink.h) AC_CHECK_HEADERS(openssl/ssl.h openssl/md5.h openssl/err.h,,AC_MSG_ERROR([ !!! OpenSSL is not properly installed on your system. !!! !!! Can not include OpenSSL headers files. !!!])) AC_CHECK_DECL([ETHERTYPE_IPV6],[],[CFLAGS="$CFLAGS -DETHERTYPE_IPV6=0x86dd"], [[@%:@include ]]) dnl ----[ Checks for libraries ]---- AC_CHECK_LIB(crypt, crypt,,AC_MSG_ERROR([crypt() function is required])) AC_CHECK_LIB(crypto, MD5_Init,,AC_MSG_ERROR([OpenSSL libraries are required])) AC_CHECK_LIB(ssl, SSL_CTX_new,,AC_MSG_ERROR([OpenSSL libraries are required])) AC_CHECK_LIB(nl-3, nl_socket_alloc, [ AC_CHECK_LIB(nl-genl-3, genl_connect, [ USE_NL="LIBIPVS_USE_NL" CFLAGS="$CFLAGS $(pkg-config --cflags libnl-genl-3.0)" LIBS="$LIBS $(pkg-config --libs libnl-genl-3.0)" ], [ AC_MSG_ERROR([libnl-3 is installed but not libnl-gen-3. Please, install libnl-gen-3.]) ]) ], [ AC_CHECK_LIB(nl, nl_socket_modify_cb, [ USE_NL="LIBIPVS_USE_NL" CFLAGS="$CFLAGS -DFALLBACK_LIBNL1" LIBS="$LIBS $(pkg-config --libs libnl-1)" ], [ USE_NL="LIBIPVS_DONTUSE_NL" AC_MSG_WARN([keepalived will be built without libnl support.]) ]) ]) dnl ----[ Kernel version check ]---- CPPFLAGS="$CPPFLAGS -I$kernelinc" AC_MSG_CHECKING([for kernel version]) AC_TRY_RUN([ #include #include #include #if !defined(UTS_RELEASE) && !defined(LINUX_VERSION_CODE) #include #endif int main (void) { FILE *fp = fopen ("linuxinfo", "w"); if (!fp) return 1; #if defined(UTS_RELEASE) fprintf (fp, "%s\n", UTS_RELEASE); #elif defined(LINUX_VERSION_CODE) fprintf (fp, "%d.%d.%d\n", LINUX_VERSION_CODE >> 16, (LINUX_VERSION_CODE >> 8) & 0xFF, LINUX_VERSION_CODE & 0xFF); #else fprintf (fp, "0.0.0\n"); /* Let's fail gently */ #endif fclose (fp); return 0; } ], [ LINUX_MAJOR=`cat linuxinfo | cut -d'.' -f1` LINUX_MINOR=`cat linuxinfo | cut -d'.' -f2` LINUX_PATCH=`cat linuxinfo | cut -d'.' -f3` ], [ LINUX_MAJOR="0" LINUX_MINOR="0" LINUX_PATCH="0" ], [ LINUX_MAJOR="0" LINUX_MINOR="0" LINUX_PATCH="0" ]) rm -f linuxinfo if test "$kernelversion" = "2.4"; then KERN="_KRNL_2_4_" AC_MSG_RESULT([2.4]) elif test "$kernelversion" = "2.6"; then KERN="_KRNL_2_6_" AC_MSG_RESULT([2.6]) else AC_MSG_RESULT([$LINUX_MAJOR.$LINUX_MINOR.$LINUX_PATCH]) if test "$LINUX_MAJOR" = "2" && test "$LINUX_MINOR" = "6"; then KERN="_KRNL_2_6_" elif test "$LINUX_MAJOR" = "2" && test "$LINUX_MINOR" = "4"; then KERN="_KRNL_2_4_" else KERN="_KRNL_2_6_" fi if test "$LINUX_MAJOR" = "0" -a "$LINUX_MINOR" = "0" -a "$LINUX_PATCH" = "0"; then AC_MSG_WARN([Cannot determine Linux Kernel version.]) fi fi AC_SUBST(KERN) dnl ----[ Checks for LVS and VRRP support ]---- IPVS_SUPPORT="_WITHOUT_LVS_" if test "$enable_lvs" != "no"; then if test "$KERN" = "_KRNL_2_6_"; then IPVS_SUPPORT="_WITH_LVS_" else AC_CHECK_HEADER([net/ip_vs.h], [IPVS_SUPPORT="_WITH_LVS_"], [ IPVS_SUPPORT="_WITHOUT_LVS_" AC_MSG_WARN([keepalived will be built without LVS support.]) ]) fi fi if test "$IPVS_SUPPORT" = "_WITHOUT_LVS_" -a "$enable_vrrp" = "no"; then AC_MSG_ERROR([keepalived MUST be compiled at least with LVS or VRRP framework]) fi dnl ----[ IPVS syncd support probe ]--- IPVS_SYNCD="_WITHOUT_IPVS_SYNCD_" if test "$IPVS_SUPPORT" = "_WITH_LVS_"; then AC_MSG_CHECKING([for IPVS syncd support]) if test "$KERN" = "_KRNL_2_6_"; then IPVS_SYNCD="_HAVE_IPVS_SYNCD_" elif test "_KRNL_2_4_"; then IPVS_SYNCD="_HAVE_IPVS_SYNCD_" else IPVS_SYNCD="_WITHOUT_IPVS_SYNCD_" fi if test "${IPVS_SUPPORT}" = "_WITHOUT_LVS_" -o "$enable_lvs_syncd" = "no"; then IPVS_SYNCD="_WITHOUT_IPVS_SYNCD_" fi if test "$IPVS_SYNCD" = "_HAVE_IPVS_SYNCD_"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi AC_SUBST(IPVS_SYNCD) dnl ----[ Checks for kernel netlink support ]---- VRRP_SUPPORT="_WITHOUT_VRRP_" if test "$enable_vrrp" != "no"; then VRRP_SUPPORT="_WITH_VRRP_" fi dnl ----[ Checks for kernel VMAC support ]---- CPPFLAGS="$CPPFLAGS -I$kernelinc" AC_MSG_CHECKING([for kernel macvlan support]) AC_TRY_COMPILE([ #include #include int macvlan; ], [ macvlan = IFLA_MACVLAN_MODE; macvlan = MACVLAN_MODE_PRIVATE; ], [ MACVLAN_SUPPORT=yes ], []); if test "$MACVLAN_SUPPORT" = "yes"; then VRRP_VMAC="_HAVE_VRRP_VMAC_" AC_MSG_RESULT([yes]) else VRRP_VMAC="_WITHOUT_VRRP_VMAC_" AC_MSG_RESULT([no]) fi AC_SUBST(VRRP_VMAC) dnl ----[ Checks for SNMP support ]---- SNMP_SUPPORT="_WITHOUT_SNMP_" if test "$enable_snmp" = "yes"; then AC_PATH_TOOL([NETSNMP_CONFIG], [net-snmp-config], [no]) if test x"$NETSNMP_CONFIG" = x"no"; then AC_MSG_ERROR([unable to find net-snmp-config]) fi NETSNMP_LIBS=`${NETSNMP_CONFIG} --agent-libs` #NETSNMP_CFLAGS="`${NETSNMP_CONFIG} --base-cflags`" #CFLAGS="${NETSNMP_CFLAGS} $CFLAGS" LIBS="${NETSNMP_LIBS} $LIBS" AC_MSG_CHECKING([whether C compiler supports flag "${NETSNMP_LIBS}" from Net-SNMP]) AC_LINK_IFELSE([AC_LANG_PROGRAM([ int main(void); ], [ { return 0; } ])],[AC_MSG_RESULT(yes)],[ AC_MSG_RESULT(no) AC_MSG_ERROR([incorrect CFLAGS from net-snmp-config])]) # Do we have a usable header? AC_CHECK_HEADERS([net-snmp/agent/util_funcs.h],,,[ @%:@include @%:@include @%:@include @%:@include @%:@include ]) SNMP_SUPPORT="_WITH_SNMP_" fi AC_SUBST(SNMP_SUPPORT) dnl ----[ SHA1 or not ? ]---- SHA1_SUPPORT="_WITHOUT_SHA1_" if test "${enable_sha1}" = "yes"; then CFLAGS="$CFLAGS -DFEAT_SHA1" AC_CHECK_HEADERS(openssl/sha.h,,AC_MSG_ERROR([unable to find openssl/sha.h])) AC_CHECK_LIB(crypto, SHA1_Init,,AC_MSG_ERROR([SHA1 in OpenSSL required])) SHA1_SUPPORT="_WITH_SHA1_" fi AC_SUBST(SHA1_SUPPORT) dnl ----[ check for SO_MARK support ]---- if test "${enable_fwmark}" = "no"; then SO_MARK_SUPPORT="_WITHOUT_SO_MARK_" else AC_CHECK_DECL(SO_MARK,,AC_MSG_ERROR([No SO_MARK declaration in headers]), #include ) SO_MARK_SUPPORT="_WITH_SO_MARK_" fi AC_SUBST(SO_MARK_SUPPORT) dnl ----[ Debug or not ? ]---- if test "${enable_debug}" = "yes"; then DFLAGS="-D_DEBUG_" AC_SUBST(DFLAGS) fi dnl ----[ Profiling or not ? ]---- if test "${enable_profile}" = "yes"; then CFLAGS="$CFLAGS -pg" fi AC_SUBST(VERSION) AC_SUBST(VERSION_DATE) AC_SUBST(IPVS_SUPPORT) AC_SUBST(USE_NL) AC_SUBST(VRRP_SUPPORT) dnl ----[ Checks for typedefs, structures, and compiler characteristics ]---- AC_C_CONST AC_TYPE_PID_T AC_HEADER_TIME dnl ----[ Checks for library functions ]---- AC_PROG_GCC_TRADITIONAL AC_FUNC_MEMCMP AC_TYPE_SIGNAL AC_CHECK_FUNCS(gettimeofday select socket strerror strtol uname) dnl ----[ Process output target ]---- OUTPUT_TARGET="$OUTPUT_TARGET keepalived/Makefile lib/Makefile" if test "${VRRP_SUPPORT}" = "_WITH_VRRP_"; then OUTPUT_TARGET="$OUTPUT_TARGET keepalived/vrrp/Makefile" fi if test "$IPVS_SUPPORT" = "_WITH_LVS_"; then OUTPUT_TARGET="$OUTPUT_TARGET keepalived/check/Makefile" if test "$KERN" = "_KRNL_2_6_"; then OUTPUT_TARGET="$OUTPUT_TARGET keepalived/libipvs-2.6/Makefile" elif test "$KERN" = "_KRNL_2_4_"; then OUTPUT_TARGET="$OUTPUT_TARGET keepalived/libipvs-2.4/Makefile" fi fi AC_OUTPUT($OUTPUT_TARGET) dnl ----[ Display current configuration ]---- cat < keepalived-1.2.13/doc/0000775000175000017500000000000012334072037014273 5ustar acassenacassenkeepalived-1.2.13/doc/NOTE_vrrp_vmac.txt0000644000175000017500000000527412256127641017673 0ustar acassenacassen Note on using VRRP with Virtual MAC address ============================================= Alexandre Cassen July 11th 2012 To reduce takeover impact, some networking environment would require using VRRP with VMAC address. To reach that goal Keepalived VRRP framework implements VMAC support by the invocation of 'use_vmac' keyword in configuration file. Internally, Keepalived code will bring up virtual interfaces, each interface dedicated to a specific virtual_router. Keepalived uses Linux kernel macvlan driver to defines thoses interfaces. It is then mandatory to use kernel compiled with macvlan support. In addition we can mention that VRRP VMAC will work only with kernel including the following patch : http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commitdiff;h=729e72a10930ef765c11a5a35031ba47f18221c4 By default MACVLAN interface are in VEPA mode which filters out received packets whose MAC source address matches that of the MACVLAN interface. Setting MACVLAN interface in private mode will not filter based on source MAC address. Alternatively, you can specify 'vmac_xmit_base' which will cause the VRRP messages to be transmitted and received on the underlying interface whilst ARP will happen from the the VMAC interface. You may also need to tweak your physical interfaces to play around with well known ARP issues. If you have issues, try the following configurations : 1) Global configuration net.ipv4.conf.all.arp_ignore = 1 net.ipv4.conf.all.arp_announce = 1 net.ipv4.conf.all.arp_filter = 0 2) Physical interface configuration For the physical ethernet interface running VRRP instance use: net.ipv4.conf.eth0.arp_filter = 1 3) VMAC interface consider the following VRRP configuration : vrrp_instance instance1 { state BACKUP interface eth0 virtual_router_id 250 use_vmac priority 150 advert_int 1 virtual_ipaddress { 10.0.0.254 } } The 'use_vmac' keyword will drive keepalived code to create a macvlan interface named 'vrrp.250' (default internal paradigm is vrrp.{virtual_router_id}, you can override this naming by giving an argument to 'use_vmac' keyword, eg: use_vmac vrrp250). you then need to configure interface with : net.ipv4.conf.vrrp.250.arp_filter = 0 net.ipv4.conf.vrrp.250.accept_local = 1 (this is needed for the address owner case) you can create notify_master script to automate this configuration step for you : vrrp_instance instance1 { state BACKUP interface eth0 virtual_router_id 250 use_vmac priority 150 advert_int 1 virtual_ipaddress { 10.0.0.254 } notify_master "/usr/local/bin/vmac_tweak.sh vrrp.250" } keepalived-1.2.13/doc/keepalived.conf.SYNOPSIS0000644000175000017500000004146012334072037020544 0ustar acassenacassenThis file describe all the Keepalived available keywords. The keepalived.conf file is compounded by three configurations parts : * Globals configurations * VRRP configuration * LVS configuration 0. Comment string There is 2 valid comment valid string : # or ! If you want to add comment in you configuration file use this char. 1. Globals configurations This block is divided in 2 sub-block : * Global definitions * Static routes 1.1. Global definitions The configuration block looks like : global_defs { # Block identification notification_email { # Email to send alertes to # Standard email address ... } notification_email_from # Email From dealing with SMTP proto smtp_server # SMTP server IP address smtp_connect_timeout # Number of seconds timeout connect # remote SMTP server router_id # String identifying router vrrp_mcast_group4 # optional, default 224.0.0.18 vrrp_mcast_group6 # optional, default ff02::12 } linkbeat_use_polling # Use media link failure detection polling fashion 1.2. Static addresses The configuration block looks like : static_ipaddress { # block identification / brd dev scope / brd dev scope ... } SCOPE can take the following values : * site * link * host * nowhere * global 1.3. Static routes The configuration block looks like : static_routes { # block identification src [to] / via|gw dev scope table # to is optional src [to] / via|gw dev scope table # to is optional src [to] / via|gw or dev scope table # will use multipath route blackhole [/] ... } SCOPE can take the following values : * site * link * host * nowhere * global 2. VRRP configuration This block is divided in 3 sub-block : * VRRP scripts * VRRP synchronization group * VRRP instance 2.1. VRRP scripts The configuration block looks like : vrrp_script { # VRRP script declaration script # script to run periodically interval # run the script this every seconds weight # adjust priority by this weight fall # required number of failures for KO switch rise # required number of successes for OK switch } The script will be executed periodically, every seconds. Its exit code will be recorded for all VRRP instances which will want to monitor it. Note that the script will only be executed if at least one VRRP instance monitors it with a non-zero weight. Thus, any number of scripts may be declared without taking the system down. If unspecified, the weight equals 2, which means that a success will add +2 to the priority of all VRRP instances which monitor it. On the opposite, a negative weight will be subtracted from the initial priority in case of failure. 2.2. VRRP synchronization group The configuration block looks like : vrrp_sync_group { # VRRP sync group declaration group { # group of instance to sync together # a # set ... # of VRRP_Instance string } notify_master | # Script to run during MASTER transit notify_backup | # Script to run during BACKUP transit notify_fault | # Script to run during FAULT transit notify | # Script to run during ANY state transit (1) smtp_alert # Send email notif during state transit } (1) The "notify" script is called AFTER the corresponding notify_* script has been called, and is given exactly 4 arguments (the whole string is interpreted as a litteral filename so don't add parameters!): $1 = A string indicating whether it's a "GROUP" or an "INSTANCE" $2 = The name of said group or instance $3 = The state it's transitioning to ("MASTER", "BACKUP" or "FAULT") $4 = The priority value $1 and $3 are ALWAYS sent in uppercase, and the possible strings sent are the same ones listed above ("GROUP"/"INSTANCE", "MASTER"/"BACKUP"/"FAULT"). Important: for a SYNC group to run reliably, it is vital that all instances in the group are MASTER or that they are all either BACKUP or FAULT. A situation with half instances having higher priority on machine A half others with higher priority on machine B will lead to constant re-elections. For this reason, when instances are grouped, their tracking weights are automatically set to zero, in order to avoid inconsistent priorities across instances. 2.3. VRRP instance The configuration block looks like : vrrp_instance { # VRRP instance declaration use_vmac # Use VRRP Virtual MAC vmac_xmit_base # Send/Recv VRRP messages from base # interface instead of VMAC interface native_ipv6 # Force instance to use IPv6 # when using mixed IPv4&IPv6 conf state MASTER|BACKUP # Start-up default state interface # Binding interface track_interface { # Interfaces state we monitor weight ... } track_script { # Scripts state we monitor weight ... } dont_track_primary # (default unset) ignore VRRP interface faults. # useful for cross-connect VRRP config. mcast_src_ip # src_ip to use into the VRRP packets unicast_src_ip # src_ip to use into the VRRP packets (alias to mcast_src_ip) unicast_peer { # Do not use multicast, instead send VRRP # adverts to following list of ip address ... # in unicast design fashion } lvs_sync_daemon_interface # Binding interface for lvs syncd garp_master_delay # delay for gratuitous ARP after MASTER # state transition garp_master_refresh # Periodic delay in seconds sending # gratuitous ARP while in MASTER state virtual_router_id # VRRP VRID priority # VRRP PRIO advert_int # VRRP Advert interval (use default) authentication { # Authentication block auth_type PASS|AH # Simple Passwd or IPSEC AH auth_pass # Password string (up to 8 characters) } virtual_ipaddress { # VRRP IP addres block / brd dev scope label