keepalived-1.2.7/0000775000175000017500000000000012017252421013444 5ustar acassenacassenkeepalived-1.2.7/keepalived.spec.in0000664000175000017500000001215512001611314017033 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.2 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.7/configure0000775000175000017500000050367512012246161015372 0ustar acassenacassen#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.65. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. 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 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" 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 : # 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. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} 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_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 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=$?; test $as_status -eq 0 && as_status=1 if test "$3"; then as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 fi $as_echo "$as_me: error: $1" >&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; } # 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 -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' 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 if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # 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, 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 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_snmp 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=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 $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 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 --enable-snmp compile with SNMP 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.65 Copyright (C) 2009 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; test "x$as_lineno_stack" = x && { as_lineno=; 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; } >/dev/null && { 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; test "x$as_lineno_stack" = x && { as_lineno=; 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; test "x$as_lineno_stack" = x && { as_lineno=; 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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; 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.$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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; 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; test "x$as_lineno_stack" = x && { as_lineno=; 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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; 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; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_compile # ac_fn_c_check_decl LINENO SYMBOL VAR # ------------------------------------ # Tests whether SYMBOL is declared, 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_echo "$as_me:${as_lineno-$LINENO}: checking whether $2 is declared" >&5 $as_echo_n "checking whether $2 is declared... " >&6; } if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { #ifndef $2 (void) $2; #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; test "x$as_lineno_stack" = x && { as_lineno=; 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 || $as_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; test "x$as_lineno_stack" = x && { as_lineno=; 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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; 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; test "x$as_lineno_stack" = x && { as_lineno=; 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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; 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; test "x$as_lineno_stack" = x && { as_lineno=; 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.65. 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 cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX 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 cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX 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 cat <<\_ASBOX ## ------------------- ## ## File substitutions. ## ## ------------------- ## _ASBOX 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 cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX 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 ac_site_file1=$CONFIG_SITE 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" 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 keepalived/include/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 test "${ac_cv_prog_CC+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_ac_ct_CC+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_CC+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_CC+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_CC+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_ac_ct_CC+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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_set_status 77 as_fn_error "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 test "${ac_cv_objext+set}" = set; 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 test "${ac_cv_c_compiler_gnu+set}" = set; 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 test "${ac_cv_prog_cc_g+set}" = set; 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 test "${ac_cv_prog_cc_c89+set}" = set; 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 #include #include /* 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 for ac_t in install-sh install.sh shtool; do if test -f "$ac_dir/$ac_t"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/$ac_t -c" break 2 fi done 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 test "${ac_cv_path_install+set}" = set; 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 { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_STRIP+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_ac_ct_STRIP+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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-snmp was given. if test "${enable_snmp+set}" = set; then : enableval=$enable_snmp; 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 test "${ac_cv_prog_CPP+set}" = set; 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.$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.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f 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.$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.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f 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 test "${ac_cv_path_GREP+set}" = set; 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" { test -f "$ac_path_GREP" && $as_test_x "$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 test "${ac_cv_path_EGREP+set}" = set; 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" { test -f "$ac_path_EGREP" && $as_test_x "$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 test "${ac_cv_header_stdc+set}" = set; 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 test "${ac_cv_header_sys_wait_h+set}" = set; 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 " eval as_val=\$$as_ac_Header if test "x$as_val" = 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" eval as_val=\$$as_ac_Header if test "x$as_val" = 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" eval as_val=\$$as_ac_Header if test "x$as_val" = 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" = x""yes; then : else CFLAGS="$CFLAGS -DETHERTYPE_IPV6=0x86dd" 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 test "${ac_cv_lib_crypto_MD5_Init+set}" = set; 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" = x""yes; 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 test "${ac_cv_lib_ssl_SSL_CTX_new+set}" = set; 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" = x""yes; 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 poptGetContext in -lpopt" >&5 $as_echo_n "checking for poptGetContext in -lpopt... " >&6; } if test "${ac_cv_lib_popt_poptGetContext+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpopt $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 poptGetContext (); int main () { return poptGetContext (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_popt_poptGetContext=yes else ac_cv_lib_popt_poptGetContext=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_popt_poptGetContext" >&5 $as_echo "$ac_cv_lib_popt_poptGetContext" >&6; } if test "x$ac_cv_lib_popt_poptGetContext" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPOPT 1 _ACEOF LIBS="-lpopt $LIBS" else as_fn_error "Popt libraries is required" "$LINENO" 5 fi { $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 test "${ac_cv_lib_nl_nl_socket_modify_cb+set}" = set; 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" = x""yes; then : USE_NL="LIBIPVS_USE_NL" LIBS="$LIBS -lnl" 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 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" = x""yes; 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 test "${ac_cv_path_NETSNMP_CONFIG+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_path_ac_pt_NETSNMP_CONFIG+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NET_SNMP_AGENT_UTIL_FUNCS_H 1 _ACEOF fi done SNMP_SUPPORT="_WITH_SNMP_" 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 test "${ac_cv_c_const+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { /* FIXME: Include the comments suggested by Paul. */ #ifndef __cplusplus /* Ultrix mips cc rejects this. */ typedef int charset[2]; const charset cs; /* 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. */ char *t; 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 saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; }; struct s *b; 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" = x""yes; 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 test "${ac_cv_header_time+set}" = set; 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 test "${ac_cv_prog_gcc_traditional+set}" = set; 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 test "${ac_cv_func_memcmp_working+set}" = set; 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 test "${ac_cv_type_signal+set}" = set; 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" eval as_val=\$$as_ac_var if test "x$as_val" = 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 test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file 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= 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. 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 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=$?; test $as_status -eq 0 && as_status=1 if test "$3"; then as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 fi $as_echo "$as_me: error: $1" >&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 -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' 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 if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # 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.65. 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.65, with options \\"\$ac_cs_config\\" Copyright (C) 2009 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=$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"` ;; 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= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$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 -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 # 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 {' >"$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 >>"\$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 >>"\$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 < "$tmp/subs1.awk" > "$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 $(srcdir), # ${srcdir} and @srcdir@ 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[ ]*=/{ s/:*\$(srcdir):*/:/ s/:*\${srcdir}:*/:/ s/:*@srcdir@:*/:/ s/^\([^=]*=[ ]*\):*/\1/ s/:*$// 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="$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 "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 >"$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 "$tmp/subs.awk" >$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' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$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 "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$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 $? 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 < : 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.7/TODO0000664000175000017500000000002412017240230014123 0ustar acassenacassenWhatever you want ! keepalived-1.2.7/keepalived/0000775000175000017500000000000012017252420015554 5ustar acassenacassenkeepalived-1.2.7/keepalived/etc/0000775000175000017500000000000012001611314016321 5ustar acassenacassenkeepalived-1.2.7/keepalived/etc/keepalived/0000775000175000017500000000000012001611314020432 5ustar acassenacassenkeepalived-1.2.7/keepalived/etc/keepalived/keepalived.conf0000664000175000017500000000675212001611314023424 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.7/keepalived/etc/init.d/0000775000175000017500000000000012001611314017506 5ustar acassenacassenkeepalived-1.2.7/keepalived/etc/init.d/keepalived.suse.init0000664000175000017500000000740112001611314023464 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.7/keepalived/etc/init.d/keepalived.rh.init0000775000175000017500000000235212001611314023121 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.7/keepalived/etc/init.d/keepalived.init0000775000175000017500000000241012001611314022504 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 ;; *) echo "Usage: $0 {start|stop|reload|restart|condrestart|status}" exit 1 esac exit $RETVAL keepalived-1.2.7/keepalived/etc/init.d/keepalived.sysconfig0000664000175000017500000000123312001611314023544 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.7/keepalived/include/0000775000175000017500000000000012017252420017177 5ustar acassenacassenkeepalived-1.2.7/keepalived/include/check_smtp.h0000664000175000017500000000410412012246161021467 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" #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 struct _smtp_host { struct sockaddr_storage dst; struct sockaddr_storage bindto; } 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; /* Prototypes defs */ extern void install_smtp_check_keyword(void); #endif keepalived-1.2.7/keepalived/include/vrrp_scheduler.h0000664000175000017500000000376212012246161022407 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_conf_data *); extern int vrrp_dispatcher_init(thread_t *); extern int vrrp_read_dispatcher_thread(thread_t *); #endif keepalived-1.2.7/keepalived/include/daemon.h0000664000175000017500000000240012012246161020607 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.7/keepalived/include/snmp.h0000664000175000017500000000443312012246161020331 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.7/keepalived/include/smtp.h0000664000175000017500000000503712012246161020340 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 /* 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_thread_arg { int fd; int stage; int email_it; char *subject; char *body; char *buffer; long buflen; } smtp_thread_arg; /* 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\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 *, vrrp_rt *, vrrp_sgroup *, const char *, const char *); #endif keepalived-1.2.7/keepalived/include/vrrp_index.h0000664000175000017500000000274412012246161021537 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_rt *); extern void alloc_vrrp_fd_bucket(vrrp_rt *); extern void remove_vrrp_fd_bucket(vrrp_rt *); extern void set_vrrp_fd_bucket(int, vrrp_rt *); extern vrrp_rt *vrrp_index_lookup(const int, const int); #endif keepalived-1.2.7/keepalived/include/vrrp_data.h0000664000175000017500000000473412017240230021336 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" /* * 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 fd_in; int fd_out; } sock_t; /* Configuration data root */ typedef struct _vrrp_conf_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_conf_data; /* Global Vars exported */ extern vrrp_conf_data *vrrp_data; extern vrrp_conf_data *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_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_conf_data *alloc_vrrp_data(void); extern void free_vrrp_data(vrrp_conf_data *); extern void dump_vrrp_data(vrrp_conf_data *); extern void free_vrrp_sockpool(vrrp_conf_data *); #endif keepalived-1.2.7/keepalived/include/pidfile.h0000664000175000017500000000306712012246161020772 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.7/keepalived/include/vrrp_track.h0000664000175000017500000000626012017240230021525 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; /* Tracked script structure definition */ typedef struct _tracked_sc { int weight; /* tracking weight when non-zero */ vrrp_script *scr; /* script pointer, cannot be NULL */ } tracked_sc; /* 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* find_script_by_name(char *); #endif keepalived-1.2.7/keepalived/include/check_daemon.h0000664000175000017500000000243612012246161021755 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.7/keepalived/include/global_data.h0000664000175000017500000000371112013300170021573 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; /* Configuration data root */ typedef struct _conf_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; #ifdef _WITH_SNMP_ int enable_traps; #endif } conf_data_t; /* Global vars exported */ extern conf_data_t *global_data; /* Global configuration data */ /* Prototypes */ extern void alloc_email(char *); extern conf_data_t *alloc_global_data(void); extern void free_global_data(conf_data_t *); extern void dump_global_data(conf_data_t *); #endif keepalived-1.2.7/keepalived/include/check_data.h0000664000175000017500000001652012017240230021416 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 */ #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; /* 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; typedef struct _virtual_server_group { char *gname; list addr_ip; list range; list vfwmark; } virtual_server_group; /* Virtual Server definition */ typedef struct _virtual_server { char *vsgname; struct sockaddr_storage addr; real_server *s_svr; uint32_t vfwmark; uint16_t service_type; long delay_loop; int ha_suspend; 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. */ #if defined(_WITH_SNMP_) && defined(_KRNL_2_6_) && defined(_WITH_LVS_) /* Statistics */ time_t lastupdated; struct ip_vs_stats_user stats; #endif } virtual_server; /* Configuration data root */ typedef struct _check_conf_data { ssl_data_t *ssl; list vs_group; list vs; } check_conf_data; /* 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 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 &&\ !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_conf_data *check_data; extern check_conf_data *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_conf_data *alloc_check_data(void); extern void free_check_data(check_conf_data *); extern void dump_check_data(check_conf_data *); #endif keepalived-1.2.7/keepalived/include/config.h.in0000664000175000017500000000220312012246161021217 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 include file. * * Author: Jacob Rief, * * 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 _CONFIG_H #define _CONFIG_H #define LOG_FACILITY_MAX 7 #define PROG "Keepalived" #define VERSION_STRING PROG" v@VERSION@ (@VERSION_DATE@)\n" #endif keepalived-1.2.7/keepalived/include/vrrp_sync.h0000664000175000017500000000350512012246161021400 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_rt *); extern void vrrp_sync_smtp_notifier(vrrp_sgroup *); extern void vrrp_sync_set_group(vrrp_sgroup *); extern int vrrp_sync_group_up(vrrp_sgroup *); extern int vrrp_sync_leave_fault(vrrp_rt *); extern int vrrp_sync_goto_master(vrrp_rt *); extern void vrrp_sync_backup(vrrp_rt *); extern void vrrp_sync_master(vrrp_rt *); extern void vrrp_sync_master_election(vrrp_rt *); extern void vrrp_sync_fault(vrrp_rt *); #endif keepalived-1.2.7/keepalived/include/vrrp_parser.h0000664000175000017500000000220612017240230021711 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.7/keepalived/include/check_api.h0000664000175000017500000000515612017240230021261 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" /* Checkers structure definition */ typedef struct _checker { void (*free_func) (void *); void (*dump_func) (void *); int (*launch) (struct _thread *); int (*plugin_launch) (void *); virtual_server *vs; /* pointer to the checker thread virtualserver */ real_server *rs; /* pointer to the checker thread realserver */ void *data; checker_id_t id; /* Checker identifier */ int enabled; /* Activation flag */ } checker_t; /* Checkers queue */ extern list checkers_queue; /* utility macro */ #define CHECKER_ARG(X) ((X)->data) #define CHECKER_DATA(X) (((checker_t *)X)->data) #define CHECKER_GET() (CHECKER_DATA(LIST_TAIL_DATA(checkers_queue))) #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) /* Prototypes definition */ extern void init_checkers_queue(void); extern void queue_checker(void (*free_func) (void *), void (*dump_func) (void *) , int (*launch) (thread_t *) , void *); 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 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.7/keepalived/include/vrrp_snmp.h0000664000175000017500000001040612012246161021377 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_rt *); extern void vrrp_snmp_group_trap(vrrp_sgroup *); #endif keepalived-1.2.7/keepalived/include/vrrp_if.h0000664000175000017500000001107412012246161021022 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 /* 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 */ 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 */ } interface; /* Tracked interface structure definition */ typedef struct _tracked_if { int weight; /* tracking weight when non-zero */ interface *ifp; /* interface backpointer, cannot be NULL */ } tracked_if; /* Macros */ #define IF_NAME(X) ((X)->ifname) #define IF_INDEX(X) ((X)->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 *if_get_by_ifindex(const int); extern interface *if_get_by_ifname(const char *); extern int if_linkbeat(const interface *); extern int if_mii_probe(const char *); extern int if_ethtool_probe(const char *); extern void if_add_queue(interface *); 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 *, int); extern int if_leave_vrrp_group(sa_family_t, int, interface *); extern int if_setsockopt_bindtodevice(int *, interface *); 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 *); extern int if_setsockopt_priority(int *); #endif keepalived-1.2.7/keepalived/include/vrrp_notify.h0000664000175000017500000000237412012246161021737 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_rt *, int); extern int notify_group_exec(vrrp_sgroup *, int); #endif keepalived-1.2.7/keepalived/include/check_parser.h0000664000175000017500000000221212017240230021772 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.7/keepalived/include/vrrp_ndisc.h0000664000175000017500000000437112012246161021526 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 *); #endif keepalived-1.2.7/keepalived/include/layer4.h0000664000175000017500000000334712012246161020557 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" enum connect_result { connect_error, connect_in_progress, connect_timeout, connect_success }; /* Prototypes defs */ extern enum connect_result tcp_bind_connect(int, struct sockaddr_storage *, struct sockaddr_storage *); 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.7/keepalived/include/vrrp.h0000664000175000017500000002166612017240230020350 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 { /* 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 */ } vrrp_pkt; /* 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; /* parameters per virtual router -- rfc2338.6.1.2 */ typedef struct _vrrp_rt { sa_family_t family; /* AF_INET|AF_INET6 */ char *iname; /* Instance Name */ vrrp_sgroup *sync; /* Sync group we belong to */ interface *ifp; /* Interface we belong to */ int dont_track_primary; /* If set ignores ifp faults */ int vmac; /* If set try to set VRRP VMAC */ 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 */ uint32_t mcast_saddr; /* Src IP address to use in VRRP IP header */ 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 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 */ /* 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; struct timeval 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 *ipsecah_counter; } vrrp_rt; /* 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 lenght */ #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)->mcast_saddr) ? (V)->mcast_saddr : 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 vrrp_pkt *vrrp_get_header(sa_family_t, char *, int *, uint32_t *); extern int open_vrrp_send_socket(sa_family_t, int, int); extern int open_vrrp_socket(sa_family_t, int, int); extern int new_vrrp_socket(vrrp_rt *); extern void close_vrrp_socket(vrrp_rt *); extern void vrrp_send_link_update(vrrp_rt *); extern int vrrp_send_adv(vrrp_rt *, int); extern int vrrp_state_fault_rx(vrrp_rt *, char *, int); extern int vrrp_state_master_rx(vrrp_rt *, char *, int); extern int vrrp_state_master_tx(vrrp_rt *, const int); extern void vrrp_state_backup(vrrp_rt *, char *, int); extern void vrrp_state_goto_master(vrrp_rt *); extern void vrrp_state_leave_master(vrrp_rt *); extern int vrrp_ipsecah_len(void); extern int vrrp_complete_init(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_rt *, int); #endif keepalived-1.2.7/keepalived/include/check_snmp.h0000664000175000017500000001067112012246161021467 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 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 *, virtual_server *); extern void check_snmp_quorum_trap(virtual_server *); #endif keepalived-1.2.7/keepalived/include/check_ssl.h0000664000175000017500000000262712017240230021311 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.7/keepalived/include/vrrp_netlink.h0000664000175000017500000000445512012246161022075 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 */ struct nl_handle { int fd; struct sockaddr_nl snl; __u32 seq; }; /* 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 struct nl_handle nl_kernel; /* Kernel reflection channel */ extern struct nl_handle 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(struct nl_handle *, unsigned long); extern int netlink_close(struct nl_handle *); extern int netlink_talk(struct nl_handle *, 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.7/keepalived/include/vrrp_daemon.h0000664000175000017500000000240412012246161021664 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.7/keepalived/include/vrrp_vmac.h0000664000175000017500000000254412012246161021354 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" /* prototypes */ extern int netlink_link_add_vmac(vrrp_rt *); extern int netlink_link_del_vmac(vrrp_rt *); #endif keepalived-1.2.7/keepalived/include/vrrp_arp.h0000664000175000017500000000417312012246161021210 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.h" #include "vrrp_ipaddress.h" /* local definitions */ #define ETHERNET_HW_LEN 6 #define IPPROTO_ADDR_LEN 4 /* types definition */ typedef struct _m_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. */ } m_arphdr; /* 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 *); #endif keepalived-1.2.7/keepalived/include/vrrp_ipsecah.h0000664000175000017500000000431412012246161022037 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 { /* 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; typedef struct { /* rfc2402.3.3.3.1.1.1 */ u_int8_t tos; u_int16_t frag_off; u_int16_t check; } ICV_mutable_fields; /* We need to zero this fields to compute the ICV */ typedef struct { int cycle; uint32_t seq_number; } seq_counter; extern void hmac_md5(unsigned char *, int, unsigned char *, int, unsigned char *); #endif keepalived-1.2.7/keepalived/include/check_http.h0000664000175000017500000000544212012246161021471 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_arg { int retry_it; /* current number of get retry */ int url_it; /* current url checked index */ request_t *req; /* GET buffer and SSL args */ } http_arg_t ; typedef struct _url { char *path; char *digest; int status_code; } url_t; typedef struct _http_checker { int proto; struct sockaddr_storage dst; struct sockaddr_storage bindto; long connection_to; int nb_get_retry; long delay_before_retry; list url; http_arg_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:%d\r\n\r\n" /* macro utility */ #define HTTP_ARG(X) ((X)->arg) #define HTTP_REQ(X) ((X)->req) /* 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.7/keepalived/include/ipwrapper.h0000664000175000017500000000373112012246161021365 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 *, real_server *); extern void update_svr_wgt(int, virtual_server *, real_server *); extern int svr_checker_up(checker_id_t, real_server *); extern void update_svr_checker_state(int, checker_id_t, virtual_server *, real_server *); extern int init_services(void); extern int clear_services(void); extern int clear_diff_services(void); #endif keepalived-1.2.7/keepalived/include/check_tcp.h0000664000175000017500000000260112012246161021272 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" /* Checker argument structure */ typedef struct _tcp_checker { struct sockaddr_storage dst; struct sockaddr_storage bindto; int connection_to; } tcp_checker_t; /* Prototypes defs */ extern void install_tcp_check_keyword(void); #endif keepalived-1.2.7/keepalived/include/ipvswrapper.h0000664000175000017500000000612612012246161021737 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 *ipvs_get_group_by_name(char *, list); extern int ipvs_group_remove_entry(virtual_server *, virtual_server_group_entry *); extern int ipvs_cmd(int, list, virtual_server *, real_server *); 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 * vs); #endif #endif keepalived-1.2.7/keepalived/include/vrrp_ipaddress.h0000664000175000017500000000543012017240230022375 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 #include #include #include #include /* local includes */ #include "vrrp_if.h" #include "list.h" #include "vector.h" /* types definition */ typedef struct { struct ifaddrmsg ifa; union { struct { struct in_addr sin_addr; struct in_addr sin_brd; } sin; struct in6_addr sin6_addr; } u; interface *ifp; /* Interface owning IP address */ char *label; /* Alias name, e.g. eth0:1 */ int set; /* TRUE if addr is set */ } ip_address; #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_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) #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) /* prototypes */ extern void netlink_iplist(list, int); extern void free_ipaddress(void *); extern void dump_ipaddress(void *); extern void alloc_ipaddress(list, vector_t *, interface *); extern void clear_diff_address(list, list); extern void clear_diff_saddresses(void); #endif keepalived-1.2.7/keepalived/include/global_parser.h0000664000175000017500000000216312012246161022166 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.7/keepalived/include/check_misc.h0000664000175000017500000000265112012246161021444 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.7/keepalived/include/vrrp_iproute.h0000664000175000017500000000420612017240230022106 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 { uint32_t dst; /* RTA_DST */ uint8_t dmask; uint32_t gw; /* RTA_GATEWAY */ uint32_t gw2; /* Will use RTA_MULTIPATH */ uint32_t src; /* RTA_PREFSRC */ uint32_t metric; /* RTA_PRIORITY */ int index; /* RTA_OIF */ int blackhole; int scope; int table; int set; } ip_route; #define IPROUTE_DEL 0 #define IPROUTE_ADD 1 /* Macro definition */ #define ROUTE_ISEQ(X,Y) ((X)->dst == (Y)->dst && \ (X)->dmask == (Y)->dmask && \ (X)->gw == (Y)->gw && \ (X)->src == (Y)->src && \ (X)->table == (Y)->table && \ (X)->scope == (Y)->scope && \ (X)->index == (Y)->index) /* prototypes */ extern int netlink_route_ipv4(ip_route *, int); extern void netlink_rtlist_ipv4(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.7/keepalived/include/main.h0000664000175000017500000000341112012246161020273 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.7/keepalived/core/0000775000175000017500000000000012017252420016504 5ustar acassenacassenkeepalived-1.2.7/keepalived/core/main.c0000664000175000017500000002205612013300170017571 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, VERSION_STRING); fprintf(stderr, "\nUsage:\n" " %s\n" " %s -n\n" " %s -f keepalived.conf\n" " %s -d\n" " %s -h\n" " %s -v\n\n", prog, prog, prog, prog, prog, prog); fprintf(stderr, "Commands:\n" "Either long or short options are allowed.\n" " %s --vrrp -P Only run with VRRP subsystem.\n" " %s --check -C Only run with Health-checker subsystem.\n" " %s --dont-release-vrrp -V Dont remove VRRP VIPs & VROUTEs on daemon stop.\n" " %s --dont-release-ipvs -I Dont remove IPVS topology on daemon stop.\n" " %s --dont-fork -n Dont fork the daemon process.\n" " %s --use-file -f Use the specified configuration file.\n" " Default is /etc/keepalived/keepalived.conf.\n" " %s --dump-conf -d Dump the configuration data.\n" " %s --log-console -l Log message to local console.\n" " %s --log-detail -D Detailed log messages.\n" " %s --log-facility -S 0-7 Set syslog facility to LOG_LOCAL[0-7]. (default=LOG_DAEMON)\n" #ifdef _WITH_SNMP_ " %s --snmp -x Enable SNMP subsystem\n" #endif " %s --help -h Display this short inlined help screen.\n" " %s --version -v Display the version number\n" " %s --pid -p pidfile\n" " %s --checkers_pid -c checkers pidfile\n" " %s --vrrp_pid -r vrrp pidfile\n", prog, prog, prog, prog, prog, prog, prog, prog, #ifdef _WITH_SNMP_ prog, #endif prog, prog, prog, prog, prog, prog, prog); } /* Command line parser */ static void parse_cmdline(int argc, char **argv) { poptContext context; char *option_arg = NULL; int c; struct poptOption options_table[] = { {"version", 'v', POPT_ARG_NONE, NULL, 'v'}, {"help", 'h', POPT_ARG_NONE, NULL, 'h'}, {"log-console", 'l', POPT_ARG_NONE, NULL, 'l'}, {"log-detail", 'D', POPT_ARG_NONE, NULL, 'D'}, {"log-facility", 'S', POPT_ARG_STRING, &option_arg, 'S'}, {"dont-release-vrrp", 'V', POPT_ARG_NONE, NULL, 'V'}, {"dont-release-ipvs", 'I', POPT_ARG_NONE, NULL, 'I'}, {"dont-fork", 'n', POPT_ARG_NONE, NULL, 'n'}, {"dump-conf", 'd', POPT_ARG_NONE, NULL, 'd'}, {"use-file", 'f', POPT_ARG_STRING, &option_arg, 'f'}, {"vrrp", 'P', POPT_ARG_NONE, NULL, 'P'}, {"check", 'C', POPT_ARG_NONE, NULL, 'C'}, {"pid", 'p', POPT_ARG_STRING, &option_arg, 'p'}, {"checkers_pid", 'c', POPT_ARG_STRING, &option_arg, 'c'}, {"vrrp_pid", 'r', POPT_ARG_STRING, &option_arg, 'r'}, #ifdef _WITH_SNMP_ {"snmp", 'x', POPT_ARG_NONE, NULL, 'x'}, #endif {NULL, 0, 0, NULL, 0} }; context = poptGetContext(PROG, argc, (const char **) argv, options_table, 0); if ((c = poptGetNextOpt(context)) < 0) { return; } /* The first option car */ 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 'S': log_facility = LOG_FACILITY[atoi(option_arg)].facility; break; case 'f': conf_file = option_arg; break; case 'P': daemon_mode |= 1; break; case 'C': daemon_mode |= 2; break; case 'p': main_pidfile = option_arg; break; case 'c': checkers_pidfile = option_arg; break; case 'r': vrrp_pidfile = option_arg; break; #ifdef _WITH_SNMP_ case 'x': snmp = 1; break; #endif } /* the others */ /* fixme: why is this duplicated? */ while ((c = poptGetNextOpt(context)) >= 0) { switch (c) { 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 'S': log_facility = LOG_FACILITY[atoi(option_arg)].facility; break; case 'f': conf_file = option_arg; break; case 'P': daemon_mode |= 1; break; case 'C': daemon_mode |= 2; break; case 'p': main_pidfile = option_arg; break; case 'c': checkers_pidfile = option_arg; break; case 'r': vrrp_pidfile = option_arg; break; #ifdef _WITH_SNMP_ case 'x': snmp = 1; break; #endif } } /* check unexpected arguments */ if ((option_arg = (char *) poptGetArg(context))) { fprintf(stderr, "unexpected argument %s\n", option_arg); return; } /* free the allocated context */ poptFreeContext(context); } /* 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.7/keepalived/core/global_parser.c0000664000175000017500000000573012017240230021465 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" /* 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); } #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); #ifdef _WITH_SNMP_ install_keyword("enable_traps", &trap_handler); #endif } keepalived-1.2.7/keepalived/core/layer4.c0000664000175000017500000000761412017240230020054 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 "check_api.h" #include "utils.h" enum connect_result tcp_bind_connect(int fd, struct sockaddr_storage *addr, struct sockaddr_storage *bind_addr) { struct linger li = { 0 }; socklen_t addrlen; 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); /* Bind socket */ if (bind_addr && ((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) { return tcp_bind_connect(fd, addr, NULL); } 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.7/keepalived/core/pidfile.c0000664000175000017500000000501312012246161020263 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.7/keepalived/core/Makefile.in0000664000175000017500000000256112012246161020555 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@ @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 ../include/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 \ ../include/config.h ../include/global_data.h keepalived-1.2.7/keepalived/core/daemon.c0000664000175000017500000000372112012246161020116 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.7/keepalived/core/global_data.c0000664000175000017500000001001412013300170021065 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 */ conf_data_t *global_data = NULL; /* Default settings */ static void set_default_router_id(conf_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(conf_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(conf_data_t * data) { data->smtp_connection_to = DEFAULT_SMTP_CONNECTION_TIMEOUT; } static void set_default_values(conf_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); } /* email facility functions */ static void free_email(void *data_obj) { FREE(data_obj); } static void dump_email(void *data_obj) { char *addr = data_obj; 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 */ conf_data_t * alloc_global_data(void) { conf_data_t *new; new = (conf_data_t *) MALLOC(sizeof (conf_data_t)); new->email = alloc_list(free_email, dump_email); set_default_values(new); return new; } void free_global_data(conf_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(conf_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); } #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.7/keepalived/core/smtp.c0000664000175000017500000003635112013300170017633 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_thread_arg * smtp_arg) { FREE(smtp_arg->buffer); FREE(smtp_arg->subject); FREE(smtp_arg->body); FREE(smtp_arg); } static char * fetch_next_email(smtp_thread_arg * smtp_arg) { return list_element(global_data->email, smtp_arg->email_it); } /* layer4 connection handlers */ static int connection_error(thread_t * thread) { smtp_thread_arg *smtp_arg = 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_arg); return 0; } static int connection_timeout(thread_t * thread) { smtp_thread_arg *smtp_arg = 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_arg); 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_thread_arg *smtp_arg = THREAD_ARG(thread); log_message(LOG_INFO, "Remote SMTP server [%s]:%d connected." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); smtp_arg->stage = connect_success; thread_add_read(thread->master, smtp_read_thread, smtp_arg, smtp_arg->fd, global_data->smtp_connection_to); return 0; } /* SMTP protocol handlers */ static int smtp_read_thread(thread_t * thread) { smtp_thread_arg *smtp_arg; char *buffer; char *reply; int rcv_buffer_size = 0; int status = -1; smtp_arg = 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_arg->buffer; rcv_buffer_size = read(thread->u.fd, buffer + smtp_arg->buflen, SMTP_BUFFER_LENGTH - smtp_arg->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_arg->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_arg->buflen += rcv_buffer_size; buffer[smtp_arg->buflen] = 0; /* NULL terminate */ } end: /* parse the buffer, finding the last line of the response for the code */ reply = buffer; while (reply < buffer + smtp_arg->buflen) { char *p; p = strstr(reply, "\r\n"); if (!p) { memmove(buffer, reply, smtp_arg->buflen - (reply - buffer)); smtp_arg->buflen -= (reply - buffer); buffer[smtp_arg->buflen] = 0; thread_add_read(thread->master, smtp_read_thread, smtp_arg, 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_arg->buflen - (reply - buffer)); smtp_arg->buflen -= (reply - buffer); buffer[smtp_arg->buflen] = 0; if (status == -1) { thread_add_read(thread->master, smtp_read_thread, smtp_arg, thread->u.fd, global_data->smtp_connection_to); return 0; } SMTP_FSM_READ(smtp_arg->stage, thread, status); /* Registering next smtp command processing thread */ if (smtp_arg->stage != ERROR) { thread_add_write(thread->master, smtp_send_thread, smtp_arg, smtp_arg->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_thread_arg *smtp_arg = 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_arg->stage, thread); /* Handle END command */ if (smtp_arg->stage == END) { SMTP_FSM_READ(QUIT, thread, 0); return 0; } /* Registering next smtp command processing thread */ if (smtp_arg->stage != ERROR) { thread_add_read(thread->master, smtp_read_thread, smtp_arg, 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_thread_arg *smtp_arg = THREAD_ARG(thread); if (status == 220) { smtp_arg->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_arg->stage = ERROR; } return 0; } /* HELO command processing */ static int helo_cmd(thread_t * thread) { smtp_thread_arg *smtp_arg = 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_arg->stage = ERROR; FREE(buffer); return 0; } static int helo_code(thread_t * thread, int status) { smtp_thread_arg *smtp_arg = THREAD_ARG(thread); if (status == 250) { smtp_arg->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_arg->stage = ERROR; } return 0; } /* MAIL command processing */ static int mail_cmd(thread_t * thread) { smtp_thread_arg *smtp_arg = 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_arg->stage = ERROR; FREE(buffer); return 0; } static int mail_code(thread_t * thread, int status) { smtp_thread_arg *smtp_arg = THREAD_ARG(thread); if (status == 250) { smtp_arg->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_arg->stage = ERROR; } return 0; } /* RCPT command processing */ static int rcpt_cmd(thread_t * thread) { smtp_thread_arg *smtp_arg = 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_arg); snprintf(buffer, SMTP_BUFFER_MAX, SMTP_RCPT_CMD, fetched_email); if (send(thread->u.fd, buffer, strlen(buffer), 0) == -1) smtp_arg->stage = ERROR; FREE(buffer); return 0; } static int rcpt_code(thread_t * thread, int status) { smtp_thread_arg *smtp_arg = THREAD_ARG(thread); char *fetched_email; if (status == 250) { smtp_arg->email_it++; fetched_email = fetch_next_email(smtp_arg); if (!fetched_email) smtp_arg->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_arg->stage = ERROR; } return 0; } /* DATA command processing */ static int data_cmd(thread_t * thread) { smtp_thread_arg *smtp_arg = THREAD_ARG(thread); if (send(thread->u.fd, SMTP_DATA_CMD, strlen(SMTP_DATA_CMD), 0) == -1) smtp_arg->stage = ERROR; return 0; } static int data_code(thread_t * thread, int status) { smtp_thread_arg *smtp_arg = THREAD_ARG(thread); if (status == 354) { smtp_arg->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_arg->stage = ERROR; } return 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_thread_arg *smtp_arg = 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_arg->subject); /* send the subject field */ if (send(thread->u.fd, buffer, strlen(buffer), 0) == -1) smtp_arg->stage = ERROR; memset(buffer, 0, SMTP_BUFFER_MAX); snprintf(buffer, SMTP_BUFFER_MAX, SMTP_BODY_CMD, smtp_arg->body); /* send the the body field */ if (send(thread->u.fd, buffer, strlen(buffer), 0) == -1) smtp_arg->stage = ERROR; /* send the sending dot */ if (send(thread->u.fd, SMTP_SEND_CMD, strlen(SMTP_SEND_CMD), 0) == -1) smtp_arg->stage = ERROR; FREE(buffer); return 0; } static int body_code(thread_t * thread, int status) { smtp_thread_arg *smtp_arg = THREAD_ARG(thread); if (status == 250) { log_message(LOG_INFO, "SMTP alert successfully sent."); smtp_arg->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_arg->stage = ERROR; } return 0; } /* QUIT command processing */ static int quit_cmd(thread_t * thread) { smtp_thread_arg *smtp_arg = THREAD_ARG(thread); if (send(thread->u.fd, SMTP_QUIT_CMD, strlen(SMTP_QUIT_CMD), 0) == -1) smtp_arg->stage = ERROR; else smtp_arg->stage++; return 0; } static int quit_code(thread_t * thread, int status) { smtp_thread_arg *smtp_arg = THREAD_ARG(thread); /* final state, we are disconnected from the remote host */ free_smtp_all(smtp_arg); close(thread->u.fd); return 0; } /* connect remote SMTP server */ static void smtp_connect(smtp_thread_arg * smtp_arg) { enum connect_result status; if ((smtp_arg->fd = socket(global_data->smtp_server.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { DBG("SMTP connect fail to create socket."); free_smtp_all(smtp_arg); return; } status = tcp_connect(smtp_arg->fd, &global_data->smtp_server); /* Handle connection status code */ thread_add_event(master, SMTP_FSM[status].send, smtp_arg, smtp_arg->fd); } /* Main entry point */ void smtp_alert(real_server * rs, vrrp_rt * vrrp, vrrp_sgroup * vgroup, const char *subject, const char *body) { smtp_thread_arg *smtp_arg; /* 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_arg = (smtp_thread_arg *) MALLOC(sizeof (smtp_thread_arg)); smtp_arg->subject = (char *) MALLOC(MAX_HEADERS_LENGTH); smtp_arg->body = (char *) MALLOC(MAX_BODY_LENGTH); smtp_arg->buffer = (char *) MALLOC(SMTP_BUFFER_MAX); /* format subject if rserver is specified */ if (rs) { snprintf(smtp_arg->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_arg->subject, MAX_HEADERS_LENGTH, "[%s] VRRP Instance %s - %s", global_data->router_id, vrrp->iname, subject); else if (vgroup) snprintf(smtp_arg->subject, MAX_HEADERS_LENGTH, "[%s] VRRP Group %s - %s", global_data->router_id, vgroup->gname, subject); else if (global_data->router_id) snprintf(smtp_arg->subject, MAX_HEADERS_LENGTH, "[%s] %s", global_data->router_id, subject); else snprintf(smtp_arg->subject, MAX_HEADERS_LENGTH, "%s", subject); strncpy(smtp_arg->body, body, MAX_BODY_LENGTH); smtp_connect(smtp_arg); } } keepalived-1.2.7/keepalived/core/snmp.c0000664000175000017500000001651112013300170017621 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); /* 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); /* 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); 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.7/keepalived/Makefile.in0000664000175000017500000000547312012246161017632 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) rm -f include/config.h 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.7/keepalived/vrrp/0000775000175000017500000000000012017252420016545 5ustar acassenacassenkeepalived-1.2.7/keepalived/vrrp/vrrp_arp.c0000664000175000017500000000656712012246161020562 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 /* 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 *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(m_arphdr) + 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 *ipaddress) { struct ether_header *eth = (struct ether_header *) garp_buffer; m_arphdr *arph = (m_arphdr *) (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(m_arphdr) + ETHER_HDR_LEN); return len; } /* * Gratuitous ARP init/close */ void gratuitous_arp_init(void) { /* Initalize shared buffer */ garp_buffer = (char *)MALLOC(sizeof(m_arphdr) + 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.7/keepalived/vrrp/vrrp_daemon.c0000664000175000017500000001567512013300170021233 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) { /* Destroy master thread */ signal_handler_destroy(); thread_destroy_master(master); if (!(debug & 8)) shutdown_vrrp_instances(); /* Clear static entries */ netlink_rtlist_ipv4(vrrp_data->static_routes, IPROUTE_DEL); netlink_iplist(vrrp_data->static_addresses, IPADDRESS_DEL); free_interface_queue(); gratuitous_arp_close(); ndisc_close(); #ifdef _WITH_SNMP_ if (snmp) vrrp_snmp_agent_close(); #endif /* Stop daemon */ pidfile_rm(vrrp_pidfile); /* Clean data */ free_global_data(global_data); free_vrrp_sockpool(vrrp_data); free_vrrp_data(vrrp_data); free_vrrp_buffer(); #ifdef _WITH_LVS_ /* Clean ipvs related */ ipvs_stop(); #endif #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 #ifdef _WITH_LVS_ /* Initialize ipvs related */ ipvs_start(); #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; } if (reload) { clear_diff_saddresses(); clear_diff_sroutes(); clear_diff_vrrp(); clear_diff_script(); } /* Complete VRRP initialization */ if (!vrrp_complete_init()) { 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_ipv4(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 */ thread_destroy_master(master); master = thread_make_master(); free_global_data(global_data); free_interface_queue(); free_vrrp_buffer(); gratuitous_arp_close(); ndisc_close(); /* Save previous conf data */ old_vrrp_data = vrrp_data; vrrp_data = NULL; #ifdef _WITH_LVS_ /* Clean ipvs related */ ipvs_stop(); #endif /* Reload the conf */ mem_allocated = 0; vrrp_signal_init(); signal_set(SIGCHLD, thread_child_handler, master); start_vrrp(); /* Close sockpool */ free_vrrp_sockpool(old_vrrp_data); /* 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 */ log_message(LOG_ALERT, "VRRP child process(%d) died: Respawning", pid); start_vrrp_child(); 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.7/keepalived/vrrp/vrrp_data.c0000664000175000017500000003141712017240230020675 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.h" #include "memory.h" #include "utils.h" #include "logger.h" /* global vars */ vrrp_conf_data *vrrp_data = NULL; vrrp_conf_data *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 *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 *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 *vscript = data; FREE(vscript->sname); FREE_PTR(vscript->script); FREE(vscript); } static void dump_vscript(void *data) { vrrp_script *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 *ifp; if (sock->fd_in > 0) { ifp = if_get_by_ifindex(sock->ifindex); 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), fd(%d,%d)]" , sock->ifindex , sock->proto , sock->fd_in , sock->fd_out); } static void free_vrrp(void *data) { vrrp_rt *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->vip); free_list(vrrp->evip); free_list(vrrp->vroutes); FREE(vrrp); } static void dump_vrrp(void *data) { vrrp_rt *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->mcast_saddr) log_message(LOG_INFO, " Using mcast src_ip = %s", inet_ntop2(vrrp->mcast_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); 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->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"); } void alloc_vrrp_sync_group(char *gname) { int size = strlen(gname); vrrp_sgroup *new; /* Allocate new VRRP group structure */ new = (vrrp_sgroup *) MALLOC(sizeof (vrrp_sgroup)); 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 *counter; vrrp_rt *new; /* Allocate new VRRP structure */ new = (vrrp_rt *) MALLOC(sizeof (vrrp_rt)); counter = (seq_counter *) MALLOC(sizeof (seq_counter)); /* 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); list_add(vrrp_data->vrrp, new); } void alloc_vrrp_track(vector_t *strvec) { vrrp_rt *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_rt *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_rt *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_rt *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_rt *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 *new; /* Allocate new VRRP group structure */ new = (vrrp_script *) MALLOC(sizeof (vrrp_script)); 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_conf_data * alloc_vrrp_data(void) { vrrp_conf_data *new; new = (vrrp_conf_data *) MALLOC(sizeof (vrrp_conf_data)); 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_conf_data * 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_list(data->vrrp_socket_pool); FREE(data); } void free_vrrp_sockpool(vrrp_conf_data * data) { free_list(data->vrrp_socket_pool); } void dump_vrrp_data(vrrp_conf_data * 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.7/keepalived/vrrp/vrrp_ipsecah.c0000664000175000017500000000561212012246161021402 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.7/keepalived/vrrp/vrrp_parser.c0000664000175000017500000003575212017240230021266 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 *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 *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 *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 *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 *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 *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group); vgroup->smtp_alert = 1; } static void vrrp_gglobal_tracking_handler(vector_t *strvec) { vrrp_sgroup *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_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->vmac = 1; if (!vrrp->mcast_saddr) vrrp->mcast_saddr = IF_ADDR(vrrp->ifp); 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); } if (strlen(vrrp->vmac_ifname)) { log_message(LOG_INFO, "vmac_ifname=%s for vrrp_instace %s" , vrrp->vmac_ifname , vrrp->iname); } if (vrrp->ifp && !(vrrp->vmac & 2)) netlink_link_add_vmac(vrrp); } static void vrrp_native_ipv6_handler(vector_t *strvec) { vrrp_rt *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_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp_sgroup *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_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); char *name = vector_slot(strvec, 1); vrrp->ifp = if_get_by_ifname(name); if (vrrp->vmac && !(vrrp->vmac & 2)) 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_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->dont_track_primary = 1; } static void vrrp_mcastip_handler(vector_t *strvec) { vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); inet_ston(vector_slot(strvec, 1), &vrrp->mcast_saddr); } static void vrrp_vrid_handler(vector_t *strvec) { vrrp_rt *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 && strlen(vrrp->vmac_ifname) == 0) { snprintf(vrrp->vmac_ifname, IFNAMSIZ, "vrrp.%d" , vrrp->vrid); log_message(LOG_INFO, "vmac_ifname=%s for vrrp_instace %s" , vrrp->vmac_ifname , vrrp->iname); } } } static void vrrp_prio_handler(vector_t *strvec) { vrrp_rt *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_rt *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_rt *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_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->nopreempt = 1; } static void /* backwards compatibility */ vrrp_preempt_handler(vector_t *strvec) { vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->nopreempt = 0; } static void vrrp_preempt_delay_handler(vector_t *strvec) { vrrp_rt *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_rt *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_rt *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_rt *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_rt *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_rt *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_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->smtp_alert = 1; } static void vrrp_lvs_syncd_handler(vector_t *strvec) { vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); vrrp->lvs_syncd_if = set_value(strvec); } static void vrrp_garp_delay_handler(vector_t *strvec) { vrrp_rt *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_auth_type_handler(vector_t *strvec) { vrrp_rt *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_rt *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_rt *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 *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script); vscript->script = set_value(strvec); } static void vrrp_vscript_interval_handler(vector_t *strvec) { vrrp_script *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 *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 *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 *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 *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("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_mcastip_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("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.7/keepalived/vrrp/vrrp_ipaddress.c0000664000175000017500000001711112017240230021735 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 */ static int netlink_ipaddress(ip_address *ipaddress, int cmd) { 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)) { 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 *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 *ipaddr = if_data; FREE_PTR(ipaddr->label); FREE(ipaddr); } void dump_ipaddress(void *if_data) { ip_address *ipaddr = if_data; char *broadcast = (char *) MALLOC(21); char *addr_str = (char *) MALLOC(41); if (IP_IS6(ipaddr)) { inet_ntop(AF_INET6, &ipaddr->u.sin6_addr, addr_str, 41); } else { inet_ntop(AF_INET, &ipaddr->u.sin.sin_addr, addr_str, 41); if (ipaddr->u.sin.sin_brd.s_addr) snprintf(broadcast, sizeof(broadcast), " 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); } void alloc_ipaddress(list ip_list, vector_t *strvec, interface *ifp) { ip_address *new; interface *ifp_local; char *str, *p; void *addr; int i = 0, addr_idx =0; new = (ip_address *) MALLOC(sizeof(ip_address)); 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 fixe 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 { p = strchr(str, '/'); if (p) { new->ifa.ifa_prefixlen = atoi(p + 1); *p = 0; } new->ifa.ifa_family = (strchr(str, ':')) ? AF_INET6 : AF_INET; if (!new->ifa.ifa_prefixlen) new->ifa.ifa_prefixlen = (IP_IS6(new)) ? 128 : 32; 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 is trying to assign invalid VIP %s. " "skipping VIP...", str); FREE(new); return; } addr_idx = i; } i++; } list_add(ip_list, new); } /* Find an address in a list */ int address_exist(list l, ip_address *ipaddress) { ip_address *ipaddr; element e; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { ipaddr = ELEMENT_DATA(e); if (IP_FAMILY(ipaddr) == IP_FAMILY(ipaddress)) { if ((IP_IS6(ipaddress) && IP6_ISEQ(ipaddr, ipaddress)) || (!IP_IS6(ipaddress) && 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 *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.7/keepalived/vrrp/vrrp_vmac.c0000664000175000017500000001360212013300170020702 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_rt *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_rt *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_rt *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_rt *vrrp) { #ifdef _HAVE_VRRP_VMAC_ struct rtattr *linkinfo; interface *ifp; char ifname[IFNAMSIZ]; struct { struct nlmsghdr n; struct ifinfomsg ifi; char buf[256]; } req; if (!vrrp->ifp) 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))) { vrrp->ifp = ifp; /* Save ifindex for use on delete */ vrrp->vmac_ifindex = IF_INDEX(vrrp->ifp); vrrp->vmac |= 2; 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) return -1; /* * Update interface queue and vrrp instance interface binding. * bring it UP ! */ netlink_interface_lookup(); ifp = if_get_by_ifname(ifname); if (!ifp) return -1; vrrp->ifp = ifp; vrrp->vmac_ifindex = IF_INDEX(vrrp->ifp); /* For use on delete */ vrrp->vmac |= 2; 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_rt *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) status = -1; #endif return status; } keepalived-1.2.7/keepalived/vrrp/vrrp_if.c0000664000175000017500000003454712013300170020365 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 * if_get_by_ifindex(const int ifindex) { interface *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; } interface * if_get_by_ifname(const char *ifname) { interface *ifp; element e; if (LIST_ISEMPTY(if_queue)) { log_message(LOG_ERR, "Interface queue is empty"); return NULL; } for (e = LIST_HEAD(if_queue); e; ELEMENT_NEXT(e)) { ifp = ELEMENT_DATA(e); if (!strcmp(ifp->ifname, ifname)) return ifp; } log_message(LOG_ERR, "No such interface, %s", ifname); 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 * 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 *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 * ifp) { list_add(if_queue, ifp); } static int if_linkbeat_refresh_thread(thread_t * thread) { interface *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 *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 * 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; kernel_netlink_close(); } 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 *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.s_addr = htonl(INADDR_VRRP_GROUP); 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.s6_addr16[0] = htons(0xff02); imr6.ipv6mr_multiaddr.s6_addr16[7] = htons(0x12); 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 *ifp) { struct ip_mreqn 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)); /* FIXME: change this to use struct ip_mreq */ imr.imr_multiaddr.s_addr = htonl(INADDR_VRRP_GROUP); imr.imr_address.s_addr = IF_ADDR(ifp); imr.imr_ifindex = IF_INDEX(ifp); ret = setsockopt(sd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *) &imr, sizeof (struct ip_mreqn)); } else { memset(&imr6, 0, sizeof(imr6)); /* rfc5798.5.1.2.2 : destination IPv6 mcast group is * ff02:0:0:0:0:0:0:12. */ imr6.ipv6mr_multiaddr.s6_addr16[0] = htons(0xff02); imr6.ipv6mr_multiaddr.s6_addr16[7] = htons(0x12); 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 *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 *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; } keepalived-1.2.7/keepalived/vrrp/vrrp_scheduler.c0000664000175000017500000006750312017250705021757 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.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_rt *, char *, int); static void vrrp_leave_master(vrrp_rt *, char *, int); static void vrrp_leave_fault(vrrp_rt *, char *, int); static void vrrp_become_master(vrrp_rt *, char *, int); static void vrrp_goto_master(vrrp_rt *); static void vrrp_master(vrrp_rt *); static void vrrp_fault(vrrp_rt *); 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_rt *, char *, int); void (*read_to) (vrrp_rt *); } 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_rt *); } 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_rt * 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_rt *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_rt *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_rt *vrrp; vrrp_sgroup *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 *sc; tracked_if *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_rt *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 *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_rt *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_rt *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) thread_add_timer(master, vrrp_read_dispatcher_thread, sock, vrrp_timer); else 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) { 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)) return 1; } return 0; } void alloc_sock(sa_family_t family, list l, int proto, int ifindex) { sock_t *new; new = (sock_t *) MALLOC(sizeof (sock_t)); new->family = family; new->proto = proto; new->ifindex = ifindex; list_add(l, new); } static void vrrp_create_sockpool(list l) { vrrp_rt *vrrp; list p = vrrp_data->vrrp; element e; int ifindex; int proto; for (e = LIST_HEAD(p); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); ifindex = IF_INDEX(vrrp->ifp); 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)) alloc_sock(vrrp->family, l, proto, ifindex); } } 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); if (sock->fd_in == -1) sock->fd_out = -1; else sock->fd_out = open_vrrp_send_socket(sock->family, sock->proto, sock->ifindex); } } static void vrrp_set_fds(list l) { sock_t *sock; vrrp_rt *vrrp; list p = vrrp_data->vrrp; element e_sock; element e_vrrp; int proto; 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); if (vrrp->auth_type == VRRP_AUTH_AH) proto = IPPROTO_IPSEC_AH; else proto = IPPROTO_VRRP; if ((sock->ifindex == IF_INDEX(vrrp->ifp)) && (sock->proto == proto)) { 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_conf_data *conf_data) { free_list(conf_data->vrrp_socket_pool); } static void vrrp_backup(vrrp_rt * vrrp, char *buffer, int len) { struct iphdr *iph; ipsec_ah *ah; if (vrrp->family == AF_INET) { iph = (struct iphdr *) buffer; if (iph->protocol == IPPROTO_IPSEC_AH) { ah = (ipsec_ah *) (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_rt * vrrp, char *buffer, int len) { struct iphdr *iph; ipsec_ah *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 *) (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_rt * 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_rt *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_rt * 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_rt * 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_rt *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_rt *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_rt * 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_rt * vrrp) { vrrp_sgroup *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_rt *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); return vrrp->fd_in; } /* Handle dispatcher read packet */ static int vrrp_dispatcher_read(sock_t * sock) { vrrp_rt *vrrp; vrrp_pkt *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) thread_add_timer(thread->master, vrrp_read_dispatcher_thread, sock, vrrp_timer); else 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 *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 *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.7/keepalived/vrrp/vrrp_track.c0000664000175000017500000001275112017240230021070 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 *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 *ifp = NULL; tracked_if *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 *) MALLOC(sizeof (tracked_if)); tip->ifp = ifp; tip->weight = weight; list_add(track_list, tip); } vrrp_script * find_script_by_name(char *name) { element e; vrrp_script *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 *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 *vsc = NULL; tracked_sc *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 *) MALLOC(sizeof (tracked_sc)); 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 *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 *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 *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 *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 *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.7/keepalived/vrrp/Makefile.in0000664000175000017500000001023112012246161020607 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_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.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.7/keepalived/vrrp/vrrp_iproute.c0000664000175000017500000001646512017240230021461 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_iproute.h" #include "vrrp_netlink.h" #include "vrrp_if.h" #include "vrrp_data.h" #include "logger.h" #include "memory.h" #include "utils.h" /* Add/Delete IP route to/from a specific interface */ int netlink_route_ipv4(ip_route *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 = AF_INET; 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; addattr_l(&req.n, sizeof(req), RTA_DST, &iproute->dst, 4); if ((!iproute->blackhole) && (!iproute->gw2)) addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &iproute->gw, 4); 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; \ rta_addattr_l(rta, 1024, RTA_GATEWAY, x, 4); \ rtnh->rtnh_len += sizeof(struct rtattr) + 4; \ 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) addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &iproute->src, 4); 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_ipv4(list rt_list, int cmd) { ip_route *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_ipv4(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 *route = rt_data; char *log_msg = MALLOC(150); char *tmp = MALLOC(30); if (route->blackhole) { strncat(log_msg, "blackhole ", 30); } if (route->dst) { snprintf(tmp, 30, "%s/%d", inet_ntop2(route->dst), route->dmask); strncat(log_msg, tmp, 30); } if (route->gw) { snprintf(tmp, 30, " gw %s", inet_ntop2(route->gw)); strncat(log_msg, tmp, 30); } if (route->gw2) { snprintf(tmp, 30, " or gw %s", inet_ntop2(route->gw2)); strncat(log_msg, tmp, 30); } if (route->src) { snprintf(tmp, 30, " src %s", inet_ntop2(route->src)); strncat(log_msg, tmp, 30); } if (route->index) { snprintf(tmp, 30, " dev %s", IF_NAME(if_get_by_ifindex(route->index))); strncat(log_msg, tmp, 30); } if (route->table) { snprintf(tmp, 30, " table %d", route->table); strncat(log_msg, tmp, 30); } if (route->scope) { snprintf(tmp, 30, " scope %s", netlink_scope_n2a(route->scope)); strncat(log_msg, tmp, 30); } if (route->metric) { snprintf(tmp, 30, " metric %d", route->metric); strncat(log_msg, tmp, 30); } log_message(LOG_INFO, " %s", log_msg); FREE(tmp); FREE(log_msg); } void alloc_route(list rt_list, vector_t *strvec) { ip_route *new; uint32_t ipaddr = 0; interface *ifp; char *str; int i = 0; new = (ip_route *) MALLOC(sizeof(ip_route)); /* FMT parse */ while (i < vector_size(strvec)) { str = vector_slot(strvec, i); /* cmd parsing */ if (!strcmp(str, "blackhole")) { new->blackhole = 1; inet_ston(vector_slot(strvec, ++i), &new->dst); new->dmask = inet_stom(vector_slot(strvec, i)); } else if (!strcmp(str, "via") || !strcmp(str, "gw")) { inet_ston(vector_slot(strvec, ++i), &new->gw); } else if (!strcmp(str, "or")) { inet_ston(vector_slot(strvec, ++i), &new->gw2); } else if (!strcmp(str, "src")) { inet_ston(vector_slot(strvec, ++i), &new->src); } 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 fixe 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++; if (inet_ston(vector_slot(strvec, i), &ipaddr)) { inet_ston(vector_slot(strvec, i), &new->dst); new->dmask = inet_stom(vector_slot(strvec, i)); } } i++; } list_add(rt_list, new); } /* Try to find a route in a list */ int route_exist(list l, ip_route *iproute) { ip_route *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 *iproute; 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_ipv4(l, IPROUTE_DEL); return; } for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { iproute = ELEMENT_DATA(e); if (!route_exist(n, iproute) && iproute->set) { log_message(LOG_INFO, "ip route %s/%d ... , no longer exist" , inet_ntop2(iproute->dst), iproute->dmask); netlink_route_ipv4(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.7/keepalived/vrrp/vrrp_snmp.c0000664000175000017500000010726312017240230020744 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_rt*)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_rt*)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_rt*)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 *addr; int state = HEADER_STATE_STATIC_ADDRESS; if ((addr = (ip_address *) 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 *route; int state = HEADER_STATE_STATIC_ROUTE; if ((route = (ip_route *) 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 *group; if ((group = (vrrp_sgroup *) 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 *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_rt* _get_instance(oid *name, size_t name_len) { int instance; element e; vrrp_rt *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_rt *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_rt *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_rt *rt; if ((rt = (vrrp_rt *)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_rt *instance; tracked_if *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_rt *instance; tracked_sc *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_rt *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 *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.7/keepalived/vrrp/vrrp_sync.c0000664000175000017500000001670012017240230020736 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_rt * 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_rt * vrrp_get_instance(char *iname) { vrrp_rt *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 *vgroup) { vrrp_rt *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 * vgroup) { vrrp_rt *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 *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_rt * vrrp) { vrrp_sgroup *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_rt * vrrp) { vrrp_rt *isync; vrrp_sgroup *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_rt * vrrp) { vrrp_rt *isync; vrrp_sgroup *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_rt * vrrp) { vrrp_rt *isync; vrrp_sgroup *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_rt * vrrp) { vrrp_rt *isync; vrrp_sgroup *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_rt * vrrp) { vrrp_rt *isync; vrrp_sgroup *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.7/keepalived/vrrp/vrrp.c0000664000175000017500000010504212013300170017674 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_rt * 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_rt * 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_ipv4(vrrp->vroutes, cmd); return 1; } /* IP header length */ static int vrrp_iphdr_len(vrrp_rt * vrrp) { return sizeof (struct iphdr); } /* IPSEC AH header length */ int vrrp_ipsecah_len(void) { return sizeof (ipsec_ah); } /* VRRP header length */ static int vrrp_hd_len(vrrp_rt * vrrp) { int len = sizeof (vrrp_pkt); 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 */ vrrp_pkt * vrrp_get_header(sa_family_t family, char *buf, int *proto, uint32_t *saddr) { struct iphdr *iph; vrrp_pkt *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 = (vrrp_pkt *) ((char *) iph + (iph->ihl << 2) + vrrp_ipsecah_len()); break; case IPPROTO_VRRP: *proto = IPPROTO_VRRP; hd = (vrrp_pkt *) ((char *) iph + (iph->ihl << 2)); break; } } else if (family == AF_INET6) { *proto = IPPROTO_VRRP; *saddr = 0; hd = (vrrp_pkt *) buf; } return hd; } /* * IPSEC AH incoming packet check. * return 0 for a valid pkt, != 0 otherwise. */ static int vrrp_in_chk_ipsecah(vrrp_rt * vrrp, char *buffer) { struct iphdr *ip = (struct iphdr *) (buffer); ipsec_ah *ah = (ipsec_ah *) ((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 * sizeof (unsigned char *)); /* 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_rt * vrrp, ip_address *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_rt * vrrp, char *buffer) { struct iphdr *ip; int ihl, vrrp_pkt_len; ipsec_ah *ah; vrrp_pkt *hd; unsigned char *vips; ip_address *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 *) (buffer + ihl); hd = (vrrp_pkt *) (ah + vrrp_ipsecah_len()); } else { hd = (vrrp_pkt *) (buffer + ihl); } /* pointer to vrrp vips pkt zone */ vips = (unsigned char *) ((char *) hd + sizeof (vrrp_pkt)); /* MUST verify that the IP TTL is 255 */ if (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 (vrrp_pkt)) { log_message(LOG_INFO, "ip payload too short. %d and expect at least %d", ntohs(ip->tot_len) - ihl, sizeof (vrrp_pkt)); 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 */ vrrp_pkt_len = sizeof(vrrp_pkt) + VRRP_AUTH_LEN + hd->naddr * sizeof(uint32_t); } else if (vrrp->family == AF_INET6) { /* IPv6 related */ hd = (vrrp_pkt *) buffer; vrrp_pkt_len = sizeof(vrrp_pkt); } 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, vrrp_pkt_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 */ 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_ip(vrrp_rt * vrrp, char *buffer, int buflen) { 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 = htonl(INADDR_VRRP_GROUP); /* 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_rt * vrrp, char *buffer, int buflen) { ICV_mutable_fields *ip_mutable_fields; unsigned char *digest; struct iphdr *ip = (struct iphdr *) (buffer); ipsec_ah *ah = (ipsec_ah *) (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 * sizeof (unsigned char *)); 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_rt * vrrp, int prio, char *buffer) { int i = 0; vrrp_pkt *hd = (vrrp_pkt *) buffer; uint32_t *iparr; element e; ip_address *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 = in_csum((u_short *) hd, vrrp_hd_len(vrrp), 0); return 0; } /* build VRRP packet */ static void vrrp_build_pkt(vrrp_rt * vrrp, int prio) { char *bufptr; 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 */ vrrp_build_ip(vrrp, VRRP_SEND_BUFFER(vrrp), VRRP_SEND_BUFFER_SIZE(vrrp)); /* 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_rt * vrrp) { struct sockaddr_in6 dst6; struct sockaddr_in dst4; struct msghdr msg; struct iovec iov; /* 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); /* Sending path */ if (vrrp->family == AF_INET) { memset(&dst4, 0, sizeof(dst4)); dst4.sin_family = AF_INET; dst4.sin_addr.s_addr = htonl(INADDR_VRRP_GROUP); 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_port = htons(IPPROTO_VRRP); dst6.sin6_addr.s6_addr16[0] = htons(0xff02); dst6.sin6_addr.s6_addr16[7] = htons(0x12); msg.msg_name = &dst6; msg.msg_namelen = sizeof(dst6); } /* Send the packet */ return sendmsg(vrrp->fd_out, &msg, MSG_DONTROUTE); } /* Allocate the sending buffer */ static void vrrp_alloc_send_buffer(vrrp_rt * 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_rt * vrrp, int prio) { /* 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 */ vrrp_build_pkt(vrrp, prio); /* send it */ return vrrp_send_pkt(vrrp); } /* Received packet processing */ int vrrp_check_packet(vrrp_rt * 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_rt * vrrp, ip_address * 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_rt * vrrp) { int j; ip_address *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_rt * 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); /* 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_rt * vrrp) { /* * Send an advertisement. To force a new master * election. */ if (vrrp->sync && !vrrp_sync_goto_master(vrrp)) 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_rt * 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_rt * 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); #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_rt * vrrp, char *buf, int buflen) { vrrp_pkt *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_rt * 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; } vrrp_send_adv(vrrp, (prio == VRRP_PRIO_OWNER) ? VRRP_PRIO_OWNER : vrrp->effective_priority); return ret; } int vrrp_state_master_rx(vrrp_rt * vrrp, char *buf, int buflen) { vrrp_pkt *hd = NULL; int ret = 0, proto = 0; uint32_t saddr = 0; ipsec_ah *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 *) (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) > VRRP_PKT_SADDR(vrrp))) { log_message(LOG_INFO, "VRRP_Instance(%s) Received higher prio advert" , vrrp->iname); if (proto == IPPROTO_IPSEC_AH) { ah = (ipsec_ah *) (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) { 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_rt * vrrp, char *buf, int buflen) { vrrp_pkt *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_rt * 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) { interface *ifp; int fd = -1; /* Retreive interface */ 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_setsockopt_mcast_loop(family, &fd); if_setsockopt_priority(&fd); if (fd < 0) return -1; } else if (family == AF_INET6) { /* Set v6 related */ 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) { interface *ifp; int fd = -1; /* Retreive interface */ 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_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_rt * vrrp) { if_leave_vrrp_group(vrrp->family, vrrp->fd_in, vrrp->ifp); close(vrrp->fd_out); } int new_vrrp_socket(vrrp_rt * vrrp) { int old_fd = vrrp->fd_in; int proto; /* 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; vrrp->fd_in = open_vrrp_socket(vrrp->family, proto, IF_INDEX(vrrp->ifp)); vrrp->fd_out = open_vrrp_send_socket(vrrp->family, proto, IF_INDEX(vrrp->ifp)); 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_rt *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) 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_rt * 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_rt *vrrp; vrrp_sgroup *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; } /* Try to find a VRRP instance */ static vrrp_rt * vrrp_exist(vrrp_rt * old_vrrp) { element e; list l = vrrp_data->vrrp; vrrp_rt *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_rt * old_vrrp, int type) { vrrp_rt *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_rt * old_vrrp) { vrrp_rt *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_rt * old_vrrp) { /* Keep VRRP state, ipsec AH seq_number */ vrrp_rt *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)); #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_rt *vrrp; if (LIST_ISEMPTY(l)) return; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vrrp = ELEMENT_DATA(e); vrrp_rt *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) 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 && !new_vrrp->vmac) { 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 *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.7/keepalived/vrrp/vrrp_netlink.c0000664000175000017500000004151012012246161021427 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 */ struct nl_handle nl_kernel; /* Kernel reflection channel */ struct nl_handle nl_cmd; /* Command channel */ /* Create a socket to netlink interface */ int netlink_socket(struct nl_handle *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); return ret; } /* Close a netlink socket */ int netlink_close(struct nl_handle *nl) { close(nl->fd); return 0; } /* Set netlink socket channel as blocking */ int netlink_set_block(struct nl_handle *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(struct nl_handle *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; } /* Our netlink parser */ static int netlink_parse_info(int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), struct nl_handle *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"); 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(struct nl_handle *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(struct nl_handle *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 *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) return 0; /* Fill the interface structure */ ifp = (interface *) MALLOC(sizeof (interface)); memcpy(ifp->ifname, name, strlen(name)); ifp->ifindex = ifi->ifi_index; ifp->flags = ifi->ifi_flags; ifp->mtu = *(int *) RTA_DATA(tb[IFLA_MTU]); ifp->hw_type = ifi->ifi_type; 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 */ 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 *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 */ 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) { struct nl_handle 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) { struct nl_handle 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 *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 */ ifp = if_get_by_ifindex(ifi->ifi_index); if (!ifp) return -1; /* Update flags */ 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) { if (thread->type != THREAD_READ_TIMEOUT) netlink_parse_info(netlink_broadcast_filter, &nl_kernel, NULL); thread_add_read(master, kernel_netlink, NULL, nl_kernel.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"); thread_add_read(master, kernel_netlink, NULL, 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.7/keepalived/vrrp/vrrp_notify.c0000664000175000017500000001224712012246161021300 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_rt * 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_rt * vrrp) { return vrrp->script; } static char * get_gscript(vrrp_sgroup * 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 * 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_rt * 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 * 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.7/keepalived/vrrp/vrrp_ndisc.c0000664000175000017500000001270412012246161021066 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 *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 *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.7/keepalived/vrrp/vrrp_index.c0000664000175000017500000000502512012246161021073 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_rt *vrrp) { list_add(&vrrp_data->vrrp_index[vrrp->vrid], vrrp); } vrrp_rt * vrrp_index_lookup(const int vrid, const int fd) { vrrp_rt *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_rt *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_rt *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_rt *vrrp) { vrrp_rt *vrrp_ptr; element e; list l = &vrrp_data->vrrp_index_fd[old_fd%1024 + 1]; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vrrp_ptr = ELEMENT_DATA(e); if (IF_INDEX(vrrp_ptr->ifp) == IF_INDEX(vrrp->ifp)) { vrrp_ptr->fd_in = vrrp->fd_in; vrrp_ptr->fd_out = vrrp->fd_out; } } } keepalived-1.2.7/keepalived/libipvs-2.6/0000775000175000017500000000000012017252420017527 5ustar acassenacassenkeepalived-1.2.7/keepalived/libipvs-2.6/libipvs.c0000664000175000017500000007006412013300170021342 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 #include "ip_vs.h" #include "libipvs.h" typedef struct ipvs_servicedest_s { struct ip_vs_service_kern svc; struct ip_vs_dest_kern dest; } ipvs_servicedest_t; static int sockfd = -1; static void* ipvs_func = NULL; struct ip_vs_getinfo ipvs_info; #ifdef LIBIPVS_USE_NL struct nl_handle *sock = NULL; int family, try_nl = 1; #endif #define CHECK_IPV4(s, ret) if (s->af && s->af != AF_INET) \ { errno = EAFNOSUPPORT; return ret; } \ s->__addr_v4 = s->addr.ip; \ #ifdef LIBIPVS_USE_NL struct nl_msg *ipvs_nl_message(int cmd, int flags) { struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return NULL; genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, flags, cmd, IPVS_GENL_VERSION); return msg; } static int ipvs_nl_noop_cb(struct nl_msg *msg, void *arg) { return NL_OK; } int ipvs_nl_send_message(struct nl_msg *msg, nl_recvmsg_msg_cb_t func, void *arg) { int err = EINVAL; sock = nl_handle_alloc(); if (!sock) { nlmsg_free(msg); return -1; } if (genl_connect(sock) < 0) goto fail_genl; family = genl_ctrl_resolve(sock, IPVS_GENL_NAME); if (family < 0) goto fail_genl; /* To test connections and set the family */ if (msg == NULL) { nl_handle_destroy(sock); sock = NULL; return 0; } if (nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, func, arg) != 0) goto fail_genl; if (nl_send_auto_complete(sock, msg) < 0) goto fail_genl; if ((err = -nl_recvmsgs_default(sock)) > 0) goto fail_genl; nlmsg_free(msg); nl_handle_destroy(sock); return 0; fail_genl: nl_handle_destroy(sock); sock = NULL; nlmsg_free(msg); errno = err; return -1; } #endif int ipvs_init(void) { socklen_t len; ipvs_func = ipvs_init; #ifdef LIBIPVS_USE_NL if (ipvs_nl_send_message(NULL, NULL, NULL) == 0) { return ipvs_getinfo(); } try_nl = 0; #endif len = sizeof(ipvs_info); if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) return -1; if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_INFO, (char *)&ipvs_info, &len)) return -1; return 0; } #ifdef LIBIPVS_USE_NL static int ipvs_getinfo_parse_cb(struct nl_msg *msg, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(msg); struct nlattr *attrs[IPVS_INFO_ATTR_MAX + 1]; if (genlmsg_parse(nlh, 0, attrs, IPVS_INFO_ATTR_MAX, ipvs_info_policy) != 0) return -1; if (!(attrs[IPVS_INFO_ATTR_VERSION] && attrs[IPVS_INFO_ATTR_CONN_TAB_SIZE])) return -1; ipvs_info.version = nla_get_u32(attrs[IPVS_INFO_ATTR_VERSION]); ipvs_info.size = nla_get_u32(attrs[IPVS_INFO_ATTR_CONN_TAB_SIZE]); return NL_OK; } #endif int ipvs_getinfo(void) { socklen_t len; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg; msg = ipvs_nl_message(IPVS_CMD_GET_INFO, 0); if (msg) return ipvs_nl_send_message(msg, ipvs_getinfo_parse_cb, NULL); return -1; } #endif ipvs_func = ipvs_getinfo; len = sizeof(ipvs_info); return getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_INFO, (char *)&ipvs_info, &len); } unsigned int ipvs_version(void) { return ipvs_info.version; } int ipvs_flush(void) { #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_FLUSH, 0); if (msg && (ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL) == 0)) return 0; return -1; } #endif return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_FLUSH, NULL, 0); } #ifdef LIBIPVS_USE_NL static int ipvs_nl_fill_service_attr(struct nl_msg *msg, ipvs_service_t *svc) { struct nlattr *nl_service; struct ip_vs_flags flags = { .flags = svc->flags, .mask = ~0 }; nl_service = nla_nest_start(msg, IPVS_CMD_ATTR_SERVICE); if (!nl_service) return -1; NLA_PUT_U16(msg, IPVS_SVC_ATTR_AF, svc->af); if (svc->fwmark) { NLA_PUT_U32(msg, IPVS_SVC_ATTR_FWMARK, svc->fwmark); } else { NLA_PUT_U16(msg, IPVS_SVC_ATTR_PROTOCOL, svc->protocol); NLA_PUT(msg, IPVS_SVC_ATTR_ADDR, sizeof(svc->addr), &(svc->addr)); NLA_PUT_U16(msg, IPVS_SVC_ATTR_PORT, svc->port); } NLA_PUT_STRING(msg, IPVS_SVC_ATTR_SCHED_NAME, svc->sched_name); NLA_PUT(msg, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags); NLA_PUT_U32(msg, IPVS_SVC_ATTR_TIMEOUT, svc->timeout); NLA_PUT_U32(msg, IPVS_SVC_ATTR_NETMASK, svc->netmask); nla_nest_end(msg, nl_service); return 0; nla_put_failure: return -1; } #endif int ipvs_add_service(ipvs_service_t *svc) { ipvs_func = ipvs_add_service; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_NEW_SERVICE, 0); if (!msg) return -1; if (ipvs_nl_fill_service_attr(msg, svc)) { nlmsg_free(msg); return -1; } return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); } #endif CHECK_IPV4(svc, -1); return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ADD, (char *)svc, sizeof(struct ip_vs_service_kern)); } int ipvs_update_service(ipvs_service_t *svc) { ipvs_func = ipvs_update_service; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_SET_SERVICE, 0); if (!msg) return -1; if (ipvs_nl_fill_service_attr(msg, svc)) { nlmsg_free(msg); return -1; } return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); } #endif CHECK_IPV4(svc, -1); return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_EDIT, (char *)svc, sizeof(struct ip_vs_service_kern)); } int ipvs_del_service(ipvs_service_t *svc) { ipvs_func = ipvs_del_service; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_DEL_SERVICE, 0); if (!msg) return -1; if (ipvs_nl_fill_service_attr(msg, svc)) { nlmsg_free(msg); return -1; } return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); } #endif CHECK_IPV4(svc, -1); return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_DEL, (char *)svc, sizeof(struct ip_vs_service_kern)); } int ipvs_zero_service(ipvs_service_t *svc) { ipvs_func = ipvs_zero_service; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_ZERO, 0); if (!msg) return -1; if (svc->fwmark || memcmp(&in6addr_any, &svc->addr.in6, sizeof(struct in6_addr)) || svc->port) { if (ipvs_nl_fill_service_attr(msg, svc)) { nlmsg_free(msg); return -1; } } return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); } #endif CHECK_IPV4(svc, -1); return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ZERO, (char *)svc, sizeof(struct ip_vs_service_kern)); } #ifdef LIBIPVS_USE_NL static int ipvs_nl_fill_dest_attr(struct nl_msg *msg, ipvs_dest_t *dst) { struct nlattr *nl_dest; nl_dest = nla_nest_start(msg, IPVS_CMD_ATTR_DEST); if (!nl_dest) return -1; NLA_PUT(msg, IPVS_DEST_ATTR_ADDR, sizeof(dst->addr), &(dst->addr)); NLA_PUT_U16(msg, IPVS_DEST_ATTR_PORT, dst->port); NLA_PUT_U32(msg, IPVS_DEST_ATTR_FWD_METHOD, dst->conn_flags & IP_VS_CONN_F_FWD_MASK); NLA_PUT_U32(msg, IPVS_DEST_ATTR_WEIGHT, dst->weight); NLA_PUT_U32(msg, IPVS_DEST_ATTR_U_THRESH, dst->u_threshold); NLA_PUT_U32(msg, IPVS_DEST_ATTR_L_THRESH, dst->l_threshold); nla_nest_end(msg, nl_dest); return 0; nla_put_failure: return -1; } #endif int ipvs_add_dest(ipvs_service_t *svc, ipvs_dest_t *dest) { ipvs_servicedest_t svcdest; #ifdef LIBIPVS_USE_NL ipvs_func = ipvs_add_dest; if (try_nl) { struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_NEW_DEST, 0); if (!msg) return -1; if (ipvs_nl_fill_service_attr(msg, svc)) goto nla_put_failure; if (ipvs_nl_fill_dest_attr(msg, dest)) goto nla_put_failure; return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); nla_put_failure: nlmsg_free(msg); return -1; } #endif CHECK_IPV4(svc, -1); CHECK_IPV4(dest, -1); memcpy(&svcdest.svc, svc, sizeof(svcdest.svc)); memcpy(&svcdest.dest, dest, sizeof(svcdest.dest)); return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ADDDEST, (char *)&svcdest, sizeof(svcdest)); } int ipvs_update_dest(ipvs_service_t *svc, ipvs_dest_t *dest) { ipvs_servicedest_t svcdest; ipvs_func = ipvs_update_dest; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_SET_DEST, 0); if (!msg) return -1; if (ipvs_nl_fill_service_attr(msg, svc)) goto nla_put_failure; if (ipvs_nl_fill_dest_attr(msg, dest)) goto nla_put_failure; return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); nla_put_failure: nlmsg_free(msg); return -1; } #endif CHECK_IPV4(svc, -1); CHECK_IPV4(dest, -1); memcpy(&svcdest.svc, svc, sizeof(svcdest.svc)); memcpy(&svcdest.dest, dest, sizeof(svcdest.dest)); return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_EDITDEST, (char *)&svcdest, sizeof(svcdest)); } int ipvs_del_dest(ipvs_service_t *svc, ipvs_dest_t *dest) { ipvs_servicedest_t svcdest; ipvs_func = ipvs_del_dest; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_DEL_DEST, 0); if (!msg) return -1; if (ipvs_nl_fill_service_attr(msg, svc)) goto nla_put_failure; if (ipvs_nl_fill_dest_attr(msg, dest)) goto nla_put_failure; return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); nla_put_failure: nlmsg_free(msg); return -1; } #endif CHECK_IPV4(svc, -1); CHECK_IPV4(dest, -1); memcpy(&svcdest.svc, svc, sizeof(svcdest.svc)); memcpy(&svcdest.dest, dest, sizeof(svcdest.dest)); return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_DELDEST, (char *)&svcdest, sizeof(svcdest)); } int ipvs_set_timeout(ipvs_timeout_t *to) { ipvs_func = ipvs_set_timeout; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_SET_TIMEOUT, 0); if (!msg) return -1; NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP, to->tcp_timeout); NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP_FIN, to->tcp_fin_timeout); NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_UDP, to->udp_timeout); return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); nla_put_failure: nlmsg_free(msg); return -1; } #endif return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_TIMEOUT, (char *)to, sizeof(*to)); } int ipvs_start_daemon(ipvs_daemon_t *dm) { ipvs_func = ipvs_start_daemon; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nlattr *nl_daemon; struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_NEW_DAEMON, 0); if (!msg) return -1; nl_daemon = nla_nest_start(msg, IPVS_CMD_ATTR_DAEMON); if (!nl_daemon) goto nla_put_failure; NLA_PUT_U32(msg, IPVS_DAEMON_ATTR_STATE, dm->state); NLA_PUT_STRING(msg, IPVS_DAEMON_ATTR_MCAST_IFN, dm->mcast_ifn); NLA_PUT_U32(msg, IPVS_DAEMON_ATTR_SYNC_ID, dm->syncid); nla_nest_end(msg, nl_daemon); return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); nla_put_failure: nlmsg_free(msg); return -1; } #endif return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_STARTDAEMON, (char *)dm, sizeof(*dm)); } int ipvs_stop_daemon(ipvs_daemon_t *dm) { ipvs_func = ipvs_stop_daemon; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nlattr *nl_daemon; struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_DEL_DAEMON, 0); if (!msg) return -1; nl_daemon = nla_nest_start(msg, IPVS_CMD_ATTR_DAEMON); if (!nl_daemon) goto nla_put_failure; NLA_PUT_U32(msg, IPVS_DAEMON_ATTR_STATE, dm->state); NLA_PUT_STRING(msg, IPVS_DAEMON_ATTR_MCAST_IFN, dm->mcast_ifn); NLA_PUT_U32(msg, IPVS_DAEMON_ATTR_SYNC_ID, dm->syncid); nla_nest_end(msg, nl_daemon); return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); nla_put_failure: nlmsg_free(msg); return -1; } #endif return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_STOPDAEMON, (char *)dm, sizeof(*dm)); } #ifdef LIBIPVS_USE_NL static int ipvs_parse_stats(struct ip_vs_stats_user *stats, struct nlattr *nla) { struct nlattr *attrs[IPVS_STATS_ATTR_MAX + 1]; if (nla_parse_nested(attrs, IPVS_STATS_ATTR_MAX, nla, ipvs_stats_policy)) return -1; if (!(attrs[IPVS_STATS_ATTR_CONNS] && attrs[IPVS_STATS_ATTR_INPKTS] && attrs[IPVS_STATS_ATTR_OUTPKTS] && attrs[IPVS_STATS_ATTR_INBYTES] && attrs[IPVS_STATS_ATTR_OUTBYTES] && attrs[IPVS_STATS_ATTR_CPS] && attrs[IPVS_STATS_ATTR_INPPS] && attrs[IPVS_STATS_ATTR_OUTPPS] && attrs[IPVS_STATS_ATTR_INBPS] && attrs[IPVS_STATS_ATTR_OUTBPS])) return -1; stats->conns = nla_get_u32(attrs[IPVS_STATS_ATTR_CONNS]); stats->inpkts = nla_get_u32(attrs[IPVS_STATS_ATTR_INPKTS]); stats->outpkts = nla_get_u32(attrs[IPVS_STATS_ATTR_OUTPKTS]); stats->inbytes = nla_get_u64(attrs[IPVS_STATS_ATTR_INBYTES]); stats->outbytes = nla_get_u64(attrs[IPVS_STATS_ATTR_OUTBYTES]); stats->cps = nla_get_u32(attrs[IPVS_STATS_ATTR_CPS]); stats->inpps = nla_get_u32(attrs[IPVS_STATS_ATTR_INPPS]); stats->outpps = nla_get_u32(attrs[IPVS_STATS_ATTR_OUTPPS]); stats->inbps = nla_get_u32(attrs[IPVS_STATS_ATTR_INBPS]); stats->outbps = nla_get_u32(attrs[IPVS_STATS_ATTR_OUTBPS]); return 0; } static int ipvs_services_parse_cb(struct nl_msg *msg, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(msg); struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1]; struct nlattr *svc_attrs[IPVS_SVC_ATTR_MAX + 1]; struct ip_vs_get_services **getp = (struct ip_vs_get_services **)arg; struct ip_vs_get_services *get = (struct ip_vs_get_services *)*getp; struct ip_vs_flags flags; int i = get->num_services; if (genlmsg_parse(nlh, 0, attrs, IPVS_CMD_ATTR_MAX, ipvs_cmd_policy) != 0) return -1; if (!attrs[IPVS_CMD_ATTR_SERVICE]) return -1; if (nla_parse_nested(svc_attrs, IPVS_SVC_ATTR_MAX, attrs[IPVS_CMD_ATTR_SERVICE], ipvs_service_policy)) return -1; memset(&(get->entrytable[i]), 0, sizeof(get->entrytable[i])); if (!(svc_attrs[IPVS_SVC_ATTR_AF] && (svc_attrs[IPVS_SVC_ATTR_FWMARK] || (svc_attrs[IPVS_SVC_ATTR_PROTOCOL] && svc_attrs[IPVS_SVC_ATTR_ADDR] && svc_attrs[IPVS_SVC_ATTR_PORT])) && svc_attrs[IPVS_SVC_ATTR_SCHED_NAME] && svc_attrs[IPVS_SVC_ATTR_NETMASK] && svc_attrs[IPVS_SVC_ATTR_TIMEOUT] && svc_attrs[IPVS_SVC_ATTR_FLAGS])) return -1; get->entrytable[i].af = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_AF]); if (svc_attrs[IPVS_SVC_ATTR_FWMARK]) get->entrytable[i].fwmark = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_FWMARK]); else { get->entrytable[i].protocol = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_PROTOCOL]); memcpy(&(get->entrytable[i].addr), nla_data(svc_attrs[IPVS_SVC_ATTR_ADDR]), sizeof(get->entrytable[i].addr)); get->entrytable[i].port = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_PORT]); } strncpy(get->entrytable[i].sched_name, nla_get_string(svc_attrs[IPVS_SVC_ATTR_SCHED_NAME]), IP_VS_SCHEDNAME_MAXLEN); get->entrytable[i].netmask = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_NETMASK]); get->entrytable[i].timeout = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_TIMEOUT]); nla_memcpy(&flags, svc_attrs[IPVS_SVC_ATTR_FLAGS], sizeof(flags)); get->entrytable[i].flags = flags.flags & flags.mask; if (ipvs_parse_stats(&(get->entrytable[i].stats), svc_attrs[IPVS_SVC_ATTR_STATS]) != 0) return -1; get->entrytable[i].num_dests = 0; i++; get->num_services = i; get = realloc(get, sizeof(*get) + sizeof(ipvs_service_entry_t) * (get->num_services + 1)); *getp = get; return 0; } #endif struct ip_vs_get_services *ipvs_get_services(void) { struct ip_vs_get_services *get; struct ip_vs_get_services_kern *getk; socklen_t len; int i; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg; len = sizeof(*get) + sizeof(ipvs_service_entry_t); if (!(get = malloc(len))) return NULL; get->num_services = 0; msg = ipvs_nl_message(IPVS_CMD_GET_SERVICE, NLM_F_DUMP); if (msg && (ipvs_nl_send_message(msg, ipvs_services_parse_cb, &get) == 0)) return get; free(get); return NULL; } #endif len = sizeof(*get) + sizeof(ipvs_service_entry_t) * ipvs_info.num_services; if (!(get = malloc(len))) return NULL; len = sizeof(*getk) + sizeof(struct ip_vs_service_entry_kern) * ipvs_info.num_services; if (!(getk = malloc(len))) return NULL; ipvs_func = ipvs_get_services; getk->num_services = ipvs_info.num_services; if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_SERVICES, getk, &len) < 0) { free(get); free(getk); return NULL; } memcpy(get, getk, sizeof(struct ip_vs_get_services)); for (i = 0; i < getk->num_services; i++) { memcpy(&get->entrytable[i], &getk->entrytable[i], sizeof(struct ip_vs_service_entry_kern)); get->entrytable[i].af = AF_INET; get->entrytable[i].addr.ip = get->entrytable[i].__addr_v4; } free(getk); return get; } typedef int (*qsort_cmp_t)(const void *, const void *); int ipvs_cmp_services(ipvs_service_entry_t *s1, ipvs_service_entry_t *s2) { int r, i; r = s1->fwmark - s2->fwmark; if (r != 0) return r; r = s1->af - s2->af; if (r != 0) return r; r = s1->protocol - s2->protocol; if (r != 0) return r; if (s1->af == AF_INET6) for (i = 0; !r && (i < 4); i++) r = ntohl(s1->addr.in6.s6_addr32[i]) - ntohl(s2->addr.in6.s6_addr32[i]); else r = ntohl(s1->addr.ip) - ntohl(s2->addr.ip); if (r != 0) return r; return ntohs(s1->port) - ntohs(s2->port); } void ipvs_sort_services(struct ip_vs_get_services *s, ipvs_service_cmp_t f) { qsort(s->entrytable, s->num_services, sizeof(ipvs_service_entry_t), (qsort_cmp_t)f); } #ifdef LIBIPVS_USE_NL static int ipvs_dests_parse_cb(struct nl_msg *msg, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(msg); struct nlattr *attrs[IPVS_DEST_ATTR_MAX + 1]; struct nlattr *dest_attrs[IPVS_SVC_ATTR_MAX + 1]; struct ip_vs_get_dests **dp = (struct ip_vs_get_dests **)arg; struct ip_vs_get_dests *d = (struct ip_vs_get_dests *)*dp; int i = d->num_dests; if (genlmsg_parse(nlh, 0, attrs, IPVS_CMD_ATTR_MAX, ipvs_cmd_policy) != 0) return -1; if (!attrs[IPVS_CMD_ATTR_DEST]) return -1; if (nla_parse_nested(dest_attrs, IPVS_DEST_ATTR_MAX, attrs[IPVS_CMD_ATTR_DEST], ipvs_dest_policy)) return -1; memset(&(d->entrytable[i]), 0, sizeof(d->entrytable[i])); if (!(dest_attrs[IPVS_DEST_ATTR_ADDR] && dest_attrs[IPVS_DEST_ATTR_PORT] && dest_attrs[IPVS_DEST_ATTR_FWD_METHOD] && dest_attrs[IPVS_DEST_ATTR_WEIGHT] && dest_attrs[IPVS_DEST_ATTR_U_THRESH] && dest_attrs[IPVS_DEST_ATTR_L_THRESH] && dest_attrs[IPVS_DEST_ATTR_ACTIVE_CONNS] && dest_attrs[IPVS_DEST_ATTR_INACT_CONNS] && dest_attrs[IPVS_DEST_ATTR_PERSIST_CONNS])) return -1; memcpy(&(d->entrytable[i].addr), nla_data(dest_attrs[IPVS_DEST_ATTR_ADDR]), sizeof(d->entrytable[i].addr)); d->entrytable[i].port = nla_get_u16(dest_attrs[IPVS_DEST_ATTR_PORT]); d->entrytable[i].conn_flags = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_FWD_METHOD]); d->entrytable[i].weight = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_WEIGHT]); d->entrytable[i].u_threshold = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_U_THRESH]); d->entrytable[i].l_threshold = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_L_THRESH]); d->entrytable[i].activeconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_ACTIVE_CONNS]); d->entrytable[i].inactconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_INACT_CONNS]); d->entrytable[i].activeconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_PERSIST_CONNS]); d->entrytable[i].af = d->af; if (ipvs_parse_stats(&(d->entrytable[i].stats), dest_attrs[IPVS_DEST_ATTR_STATS]) != 0) return -1; i++; d->num_dests = i; d = realloc(d, sizeof(*d) + sizeof(ipvs_dest_entry_t) * (d->num_dests + 1)); *dp = d; return 0; } #endif struct ip_vs_get_dests *ipvs_get_dests(ipvs_service_entry_t *svc) { struct ip_vs_get_dests *d; struct ip_vs_get_dests_kern *dk; socklen_t len; int i; len = sizeof(*d) + sizeof(ipvs_dest_entry_t) * svc->num_dests; if (!(d = malloc(len))) return NULL; ipvs_func = ipvs_get_dests; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg; struct nlattr *nl_service; if (svc->num_dests == 0) d = realloc(d,sizeof(*d) + sizeof(ipvs_dest_entry_t)); d->fwmark = svc->fwmark; d->protocol = svc->protocol; d->addr = svc->addr; d->port = svc->port; d->num_dests = svc->num_dests; d->af = svc->af; msg = ipvs_nl_message(IPVS_CMD_GET_DEST, NLM_F_DUMP); if (!msg) goto ipvs_nl_dest_failure; nl_service = nla_nest_start(msg, IPVS_CMD_ATTR_SERVICE); if (!nl_service) goto nla_put_failure; NLA_PUT_U16(msg, IPVS_SVC_ATTR_AF, svc->af); if (svc->fwmark) { NLA_PUT_U32(msg, IPVS_SVC_ATTR_FWMARK, svc->fwmark); } else { NLA_PUT_U16(msg, IPVS_SVC_ATTR_PROTOCOL, svc->protocol); NLA_PUT(msg, IPVS_SVC_ATTR_ADDR, sizeof(svc->addr), &svc->addr); NLA_PUT_U16(msg, IPVS_SVC_ATTR_PORT, svc->port); } nla_nest_end(msg, nl_service); if (ipvs_nl_send_message(msg, ipvs_dests_parse_cb, &d)) goto ipvs_nl_dest_failure; return d; nla_put_failure: nlmsg_free(msg); ipvs_nl_dest_failure: free(d); return NULL; } #endif if (svc->af != AF_INET) { errno = EAFNOSUPPORT; free(d); return NULL; } len = sizeof(*dk) + sizeof(struct ip_vs_dest_entry_kern) * svc->num_dests; if (!(dk = malloc(len))) return NULL; dk->fwmark = svc->fwmark; dk->protocol = svc->protocol; dk->addr = svc->addr.ip; dk->port = svc->port; dk->num_dests = svc->num_dests; if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_DESTS, dk, &len) < 0) { free(d); free(dk); return NULL; } memcpy(d, dk, sizeof(struct ip_vs_get_dests_kern)); d->af = AF_INET; d->addr.ip = d->__addr_v4; for (i = 0; i < dk->num_dests; i++) { memcpy(&d->entrytable[i], &dk->entrytable[i], sizeof(struct ip_vs_dest_entry_kern)); d->entrytable[i].af = AF_INET; d->entrytable[i].addr.ip = d->entrytable[i].__addr_v4; } free(dk); return d; } int ipvs_cmp_dests(ipvs_dest_entry_t *d1, ipvs_dest_entry_t *d2) { int r = 0, i; if (d1->af == AF_INET6) for (i = 0; !r && (i < 4); i++) r = ntohl(d1->addr.in6.s6_addr32[i]) - ntohl(d2->addr.in6.s6_addr32[i]); else r = ntohl(d1->addr.ip) - ntohl(d2->addr.ip); if (r != 0) return r; return ntohs(d1->port) - ntohs(d2->port); } void ipvs_sort_dests(struct ip_vs_get_dests *d, ipvs_dest_cmp_t f) { qsort(d->entrytable, d->num_dests, sizeof(ipvs_dest_entry_t), (qsort_cmp_t)f); } ipvs_service_entry_t * ipvs_get_service(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; len = sizeof(*svc); if (!(svc = malloc(len))) return NULL; ipvs_func = ipvs_get_service; svc->fwmark = fwmark; svc->af = af; svc->protocol = protocol; svc->addr = addr; svc->port = port; #ifdef LIBIPVS_USE_NL if (try_nl) { struct ip_vs_get_services *get; struct nl_msg *msg; ipvs_service_t tsvc; tsvc.fwmark = fwmark; tsvc.af = af; tsvc.protocol= protocol; tsvc.addr = addr; tsvc.port = port; if (!(get = malloc(sizeof(*get) + sizeof(ipvs_service_entry_t)))) goto ipvs_get_service_err2; get->num_services = 0; msg = ipvs_nl_message(IPVS_CMD_GET_SERVICE, 0); if (!msg) goto ipvs_get_service_err; if (ipvs_nl_fill_service_attr(msg, &tsvc)) goto nla_put_failure; if (ipvs_nl_send_message(msg, ipvs_services_parse_cb, &get)) goto ipvs_get_service_err; memcpy(svc, &(get->entrytable[0]), sizeof(*svc)); free(get); return svc; nla_put_failure: nlmsg_free(msg); ipvs_get_service_err: free(get); ipvs_get_service_err2: free(svc); return NULL; } #endif CHECK_IPV4(svc, NULL); if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_SERVICE, (char *)svc, &len)) { free(svc); return NULL; } svc->af = AF_INET; svc->addr.ip = svc->__addr_v4; return svc; } #ifdef LIBIPVS_USE_NL static int ipvs_timeout_parse_cb(struct nl_msg *msg, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(msg); struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1]; ipvs_timeout_t *u = (ipvs_timeout_t *)arg; if (genlmsg_parse(nlh, 0, attrs, IPVS_CMD_ATTR_MAX, ipvs_cmd_policy) != 0) return -1; if (attrs[IPVS_CMD_ATTR_TIMEOUT_TCP]) u->tcp_timeout = nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_TCP]); if (attrs[IPVS_CMD_ATTR_TIMEOUT_TCP_FIN]) u->tcp_fin_timeout = nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_TCP_FIN]); if (attrs[IPVS_CMD_ATTR_TIMEOUT_UDP]) u->udp_timeout = nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_UDP]); return NL_OK; } #endif ipvs_timeout_t *ipvs_get_timeout(void) { ipvs_timeout_t *u; socklen_t len; len = sizeof(*u); if (!(u = malloc(len))) return NULL; ipvs_func = ipvs_get_timeout; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg; memset(u, 0, sizeof(*u)); msg = ipvs_nl_message(IPVS_CMD_GET_TIMEOUT, 0); if (msg && (ipvs_nl_send_message(msg, ipvs_timeout_parse_cb, u) == 0)) return u; free(u); return NULL; } #endif if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_TIMEOUT, (char *)u, &len)) { free(u); return NULL; } return u; } #ifdef LIBIPVS_USE_NL static int ipvs_daemon_parse_cb(struct nl_msg *msg, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(msg); struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1]; struct nlattr *daemon_attrs[IPVS_DAEMON_ATTR_MAX + 1]; ipvs_daemon_t *u = (ipvs_daemon_t *)arg; int i = 0; /* We may get two daemons. If we've already got one, this is the second */ if (u[0].state) i = 1; if (genlmsg_parse(nlh, 0, attrs, IPVS_CMD_ATTR_MAX, ipvs_cmd_policy) != 0) return -1; if (nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX, attrs[IPVS_CMD_ATTR_DAEMON], ipvs_daemon_policy)) return -1; if (!(daemon_attrs[IPVS_DAEMON_ATTR_STATE] && daemon_attrs[IPVS_DAEMON_ATTR_MCAST_IFN] && daemon_attrs[IPVS_DAEMON_ATTR_SYNC_ID])) return -1; u[i].state = nla_get_u32(daemon_attrs[IPVS_DAEMON_ATTR_STATE]); strncpy(u[i].mcast_ifn, nla_get_string(daemon_attrs[IPVS_DAEMON_ATTR_MCAST_IFN]), IP_VS_IFNAME_MAXLEN); u[i].syncid = nla_get_u32(daemon_attrs[IPVS_DAEMON_ATTR_SYNC_ID]); return NL_OK; } #endif ipvs_daemon_t *ipvs_get_daemon(void) { ipvs_daemon_t *u; socklen_t len; /* note that we need to get the info about two possible daemons, master and backup. */ len = sizeof(*u) * 2; if (!(u = malloc(len))) return NULL; ipvs_func = ipvs_get_daemon; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg; memset(u, 0, len); msg = ipvs_nl_message(IPVS_CMD_GET_DAEMON, NLM_F_DUMP); if (msg && (ipvs_nl_send_message(msg, ipvs_daemon_parse_cb, u) == 0)) return u; free(u); return NULL; } #endif if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_DAEMON, (char *)u, &len)) { free(u); return NULL; } return u; } void ipvs_close(void) { #ifdef LIBIPVS_USE_NL if (try_nl) { return; } #endif close(sockfd); } const char *ipvs_strerror(int err) { unsigned int i; struct table_struct { void *func; int err; const char *message; } table [] = { { ipvs_add_service, EEXIST, "Service already exists" }, { ipvs_add_service, ENOENT, "Scheduler not found" }, { ipvs_update_service, ESRCH, "No such service" }, { ipvs_update_service, ENOENT, "Scheduler not found" }, { ipvs_del_service, ESRCH, "No such service" }, { ipvs_zero_service, ESRCH, "No such service" }, { ipvs_add_dest, ESRCH, "Service not defined" }, { ipvs_add_dest, EEXIST, "Destination already exists" }, { ipvs_update_dest, ESRCH, "Service not defined" }, { ipvs_update_dest, ENOENT, "No such destination" }, { ipvs_del_dest, ESRCH, "Service not defined" }, { ipvs_del_dest, ENOENT, "No such destination" }, { ipvs_start_daemon, EEXIST, "Daemon has already run" }, { ipvs_stop_daemon, ESRCH, "No daemon is running" }, { ipvs_get_services, ESRCH, "No such service" }, { ipvs_get_dests, ESRCH, "No such service" }, { ipvs_get_service, ESRCH, "No such service" }, { 0, EPERM, "Permission denied (you must be root)" }, { 0, EINVAL, "Invalid operation. Possibly wrong module version, address not unicast, ..." }, { 0, ENOPROTOOPT, "Protocol not available" }, { 0, ENOMEM, "Memory allocation problem" }, { 0, EOPNOTSUPP, "Operation not supported with IPv6" }, { 0, EAFNOSUPPORT, "Operation not supported with specified address family" }, { 0, EMSGSIZE, "Module is wrong version" }, }; for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { if ((!table[i].func || table[i].func == ipvs_func) && table[i].err == err) return table[i].message; } return strerror(err); } keepalived-1.2.7/keepalived/libipvs-2.6/ip_vs_nl_policy.c0000664000175000017500000000544412001611314023064 0ustar acassenacassen#include "ip_vs.h" #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.7/keepalived/libipvs-2.6/Makefile.in0000664000175000017500000000053412012246161021576 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.7/keepalived/libipvs-2.6/ip_vs.h0000664000175000017500000003616712001611314021027 0ustar acassenacassen/* * IP Virtual Server * data structure and functionality definitions */ #ifndef _IP_VS_H #define _IP_VS_H #include #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 */ /* * Destination Server Flags */ #define IP_VS_DEST_F_AVAILABLE 0x0001 /* server is available */ #define IP_VS_DEST_F_OVERLOAD 0x0002 /* server is overloaded */ /* * IPVS sync daemon states */ #define IP_VS_STATE_NONE 0x0000 /* daemon is stopped */ #define IP_VS_STATE_MASTER 0x0001 /* started as master */ #define IP_VS_STATE_BACKUP 0x0002 /* started as backup */ /* * IPVS socket options */ #define IP_VS_BASE_CTL (64+1024+64) /* base */ #define IP_VS_SO_SET_NONE IP_VS_BASE_CTL /* just peek */ #define IP_VS_SO_SET_INSERT (IP_VS_BASE_CTL+1) #define IP_VS_SO_SET_ADD (IP_VS_BASE_CTL+2) #define IP_VS_SO_SET_EDIT (IP_VS_BASE_CTL+3) #define IP_VS_SO_SET_DEL (IP_VS_BASE_CTL+4) #define IP_VS_SO_SET_FLUSH (IP_VS_BASE_CTL+5) #define IP_VS_SO_SET_LIST (IP_VS_BASE_CTL+6) #define IP_VS_SO_SET_ADDDEST (IP_VS_BASE_CTL+7) #define IP_VS_SO_SET_DELDEST (IP_VS_BASE_CTL+8) #define IP_VS_SO_SET_EDITDEST (IP_VS_BASE_CTL+9) #define IP_VS_SO_SET_TIMEOUT (IP_VS_BASE_CTL+10) #define IP_VS_SO_SET_STARTDAEMON (IP_VS_BASE_CTL+11) #define IP_VS_SO_SET_STOPDAEMON (IP_VS_BASE_CTL+12) #define IP_VS_SO_SET_RESTORE (IP_VS_BASE_CTL+13) #define IP_VS_SO_SET_SAVE (IP_VS_BASE_CTL+14) #define IP_VS_SO_SET_ZERO (IP_VS_BASE_CTL+15) #define IP_VS_SO_SET_MAX IP_VS_SO_SET_ZERO #define IP_VS_SO_GET_VERSION IP_VS_BASE_CTL #define IP_VS_SO_GET_INFO (IP_VS_BASE_CTL+1) #define IP_VS_SO_GET_SERVICES (IP_VS_BASE_CTL+2) #define IP_VS_SO_GET_SERVICE (IP_VS_BASE_CTL+3) #define IP_VS_SO_GET_DESTS (IP_VS_BASE_CTL+4) #define IP_VS_SO_GET_DEST (IP_VS_BASE_CTL+5) /* not used now */ #define IP_VS_SO_GET_TIMEOUT (IP_VS_BASE_CTL+6) #define IP_VS_SO_GET_DAEMON (IP_VS_BASE_CTL+7) #define IP_VS_SO_GET_MAX IP_VS_SO_GET_DAEMON /* * IPVS Connection Flags */ #define IP_VS_CONN_F_FWD_MASK 0x0007 /* mask for the fwd methods */ #define IP_VS_CONN_F_MASQ 0x0000 /* masquerading/NAT */ #define IP_VS_CONN_F_LOCALNODE 0x0001 /* local node */ #define IP_VS_CONN_F_TUNNEL 0x0002 /* tunneling */ #define IP_VS_CONN_F_DROUTE 0x0003 /* direct routing */ #define IP_VS_CONN_F_BYPASS 0x0004 /* cache bypass */ #define IP_VS_CONN_F_SYNC 0x0020 /* entry created by sync */ #define IP_VS_CONN_F_HASHED 0x0040 /* hashed entry */ #define IP_VS_CONN_F_NOOUTPUT 0x0080 /* no output packets */ #define IP_VS_CONN_F_INACTIVE 0x0100 /* not established */ #define IP_VS_CONN_F_OUT_SEQ 0x0200 /* must do output seq adjust */ #define IP_VS_CONN_F_IN_SEQ 0x0400 /* must do input seq adjust */ #define IP_VS_CONN_F_SEQ_MASK 0x0600 /* in/out sequence mask */ #define IP_VS_CONN_F_NO_CPORT 0x0800 /* no client port set yet */ #define IP_VS_CONN_F_TEMPLATE 0x1000 /* template, not connection */ /* Move it to better place one day, for now keep it unique */ #define NFC_IPVS_PROPERTY 0x10000 #define IP_VS_SCHEDNAME_MAXLEN 16 #define IP_VS_IFNAME_MAXLEN 16 union nf_inet_addr { __u32 all[4]; __be32 ip; __be32 ip6[4]; struct in_addr in; struct in6_addr in6; }; /* * The struct ip_vs_service_user and struct ip_vs_dest_user are * used to set IPVS rules through setsockopt. */ struct ip_vs_service_kern { /* virtual service addresses */ u_int16_t protocol; __be32 addr; /* virtual ip address */ __be16 port; u_int32_t fwmark; /* firwall mark of service */ /* virtual service options */ char sched_name[IP_VS_SCHEDNAME_MAXLEN]; unsigned flags; /* virtual service flags */ unsigned timeout; /* persistent timeout in sec */ __be32 netmask; /* persistent netmask */ }; struct ip_vs_service_user { /* virtual service addresses */ u_int16_t protocol; __be32 __addr_v4; /* virtual ip address - internal use only */ __be16 port; u_int32_t fwmark; /* firwall mark of service */ /* virtual service options */ char sched_name[IP_VS_SCHEDNAME_MAXLEN]; unsigned flags; /* virtual service flags */ unsigned timeout; /* persistent timeout in sec */ __be32 netmask; /* persistent netmask */ u_int16_t af; union nf_inet_addr addr; }; struct ip_vs_dest_kern { /* destination server address */ __be32 addr; __be16 port; /* real server options */ unsigned conn_flags; /* connection flags */ int weight; /* destination weight */ /* thresholds for active connections */ u_int32_t u_threshold; /* upper threshold */ u_int32_t l_threshold; /* lower threshold */ }; struct ip_vs_dest_user { /* destination server address */ __be32 __addr_v4; /* internal use only */ __be16 port; /* real server options */ unsigned conn_flags; /* connection flags */ int weight; /* destination weight */ /* thresholds for active connections */ u_int32_t u_threshold; /* upper threshold */ u_int32_t l_threshold; /* lower threshold */ u_int16_t af; union nf_inet_addr addr; }; /* * IPVS statistics object (for user space) */ struct ip_vs_stats_user { __u32 conns; /* connections scheduled */ __u32 inpkts; /* incoming packets */ __u32 outpkts; /* outgoing packets */ __u64 inbytes; /* incoming bytes */ __u64 outbytes; /* outgoing bytes */ __u32 cps; /* current connection rate */ __u32 inpps; /* current in packet rate */ __u32 outpps; /* current out packet rate */ __u32 inbps; /* current in byte rate */ __u32 outbps; /* current out byte rate */ }; /* The argument to IP_VS_SO_GET_INFO */ struct ip_vs_getinfo { /* version number */ unsigned int version; /* size of connection hash table */ unsigned int size; /* number of virtual services */ unsigned int num_services; }; /* The argument to IP_VS_SO_GET_SERVICE */ struct ip_vs_service_entry_kern { /* which service: user fills in these */ u_int16_t protocol; __be32 addr; /* virtual address */ __be16 port; u_int32_t fwmark; /* firwall mark of service */ /* service options */ char sched_name[IP_VS_SCHEDNAME_MAXLEN]; unsigned flags; /* virtual service flags */ unsigned timeout; /* persistent timeout */ __be32 netmask; /* persistent netmask */ /* number of real servers */ unsigned int num_dests; /* statistics */ struct ip_vs_stats_user stats; }; struct ip_vs_service_entry { /* which service: user fills in these */ u_int16_t protocol; __be32 __addr_v4; /* virtual address - internal use only*/ __be16 port; u_int32_t fwmark; /* firwall mark of service */ /* service options */ char sched_name[IP_VS_SCHEDNAME_MAXLEN]; unsigned flags; /* virtual service flags */ unsigned timeout; /* persistent timeout */ __be32 netmask; /* persistent netmask */ /* number of real servers */ unsigned int num_dests; /* statistics */ struct ip_vs_stats_user stats; u_int16_t af; union nf_inet_addr addr; }; struct ip_vs_dest_entry_kern { __be32 addr; /* destination address */ __be16 port; unsigned conn_flags; /* connection flags */ int weight; /* destination weight */ u_int32_t u_threshold; /* upper threshold */ u_int32_t l_threshold; /* lower threshold */ u_int32_t activeconns; /* active connections */ u_int32_t inactconns; /* inactive connections */ u_int32_t persistconns; /* persistent connections */ /* statistics */ struct ip_vs_stats_user stats; }; struct ip_vs_dest_entry { __be32 __addr_v4; /* destination address - internal use only */ __be16 port; unsigned conn_flags; /* connection flags */ int weight; /* destination weight */ u_int32_t u_threshold; /* upper threshold */ u_int32_t l_threshold; /* lower threshold */ u_int32_t activeconns; /* active connections */ u_int32_t inactconns; /* inactive connections */ u_int32_t persistconns; /* persistent connections */ /* statistics */ struct ip_vs_stats_user stats; u_int16_t af; union nf_inet_addr addr; }; /* The argument to IP_VS_SO_GET_DESTS */ struct ip_vs_get_dests_kern { /* which service: user fills in these */ u_int16_t protocol; __be32 addr; /* virtual address - internal use only */ __be16 port; u_int32_t fwmark; /* firwall mark of service */ /* number of real servers */ unsigned int num_dests; /* the real servers */ struct ip_vs_dest_entry_kern entrytable[0]; }; struct ip_vs_get_dests { /* which service: user fills in these */ u_int16_t protocol; __be32 __addr_v4; /* virtual address - internal use only */ __be16 port; u_int32_t fwmark; /* firwall mark of service */ /* number of real servers */ unsigned int num_dests; u_int16_t af; union nf_inet_addr addr; /* the real servers */ struct ip_vs_dest_entry entrytable[0]; }; /* The argument to IP_VS_SO_GET_SERVICES */ struct ip_vs_get_services { /* number of virtual services */ unsigned int num_services; /* service table */ struct ip_vs_service_entry entrytable[0]; }; struct ip_vs_get_services_kern { /* number of virtual services */ unsigned int num_services; /* service table */ struct ip_vs_service_entry_kern entrytable[0]; }; /* The argument to IP_VS_SO_GET_TIMEOUT */ struct ip_vs_timeout_user { int tcp_timeout; int tcp_fin_timeout; int udp_timeout; }; /* The argument to IP_VS_SO_GET_DAEMON */ struct ip_vs_daemon_user { /* sync daemon state (master/backup) */ int state; /* multicast interface name */ char mcast_ifn[IP_VS_IFNAME_MAXLEN]; /* SyncID we belong to */ int syncid; }; /* * * IPVS Generic Netlink interface definitions * */ /* Generic Netlink family info */ #define IPVS_GENL_NAME "IPVS" #define IPVS_GENL_VERSION 0x1 struct ip_vs_flags { __be32 flags; __be32 mask; }; /* Generic Netlink command attributes */ enum { IPVS_CMD_UNSPEC = 0, IPVS_CMD_NEW_SERVICE, /* add service */ IPVS_CMD_SET_SERVICE, /* modify service */ IPVS_CMD_DEL_SERVICE, /* delete service */ IPVS_CMD_GET_SERVICE, /* get info about specific service */ IPVS_CMD_NEW_DEST, /* add destination */ IPVS_CMD_SET_DEST, /* modify destination */ IPVS_CMD_DEL_DEST, /* delete destination */ IPVS_CMD_GET_DEST, /* get list of all service dests */ IPVS_CMD_NEW_DAEMON, /* start sync daemon */ IPVS_CMD_DEL_DAEMON, /* stop sync daemon */ IPVS_CMD_GET_DAEMON, /* get sync daemon status */ IPVS_CMD_SET_TIMEOUT, /* set TCP and UDP timeouts */ IPVS_CMD_GET_TIMEOUT, /* get TCP and UDP timeouts */ IPVS_CMD_SET_INFO, /* only used in GET_INFO reply */ IPVS_CMD_GET_INFO, /* get general IPVS info */ IPVS_CMD_ZERO, /* zero all counters and stats */ IPVS_CMD_FLUSH, /* flush services and dests */ __IPVS_CMD_MAX, }; #define IPVS_CMD_MAX (__IPVS_CMD_MAX - 1) /* Attributes used in the first level of commands */ enum { IPVS_CMD_ATTR_UNSPEC = 0, IPVS_CMD_ATTR_SERVICE, /* nested service attribute */ IPVS_CMD_ATTR_DEST, /* nested destination attribute */ IPVS_CMD_ATTR_DAEMON, /* nested sync daemon attribute */ IPVS_CMD_ATTR_TIMEOUT_TCP, /* TCP connection timeout */ IPVS_CMD_ATTR_TIMEOUT_TCP_FIN, /* TCP FIN wait timeout */ IPVS_CMD_ATTR_TIMEOUT_UDP, /* UDP timeout */ __IPVS_CMD_ATTR_MAX, }; #define IPVS_CMD_ATTR_MAX (__IPVS_SVC_ATTR_MAX - 1) /* * Attributes used to describe a service * * Used inside nested attribute IPVS_CMD_ATTR_SERVICE */ enum { IPVS_SVC_ATTR_UNSPEC = 0, IPVS_SVC_ATTR_AF, /* address family */ IPVS_SVC_ATTR_PROTOCOL, /* virtual service protocol */ IPVS_SVC_ATTR_ADDR, /* virtual service address */ IPVS_SVC_ATTR_PORT, /* virtual service port */ IPVS_SVC_ATTR_FWMARK, /* firewall mark of service */ IPVS_SVC_ATTR_SCHED_NAME, /* name of scheduler */ IPVS_SVC_ATTR_FLAGS, /* virtual service flags */ IPVS_SVC_ATTR_TIMEOUT, /* persistent timeout */ IPVS_SVC_ATTR_NETMASK, /* persistent netmask */ IPVS_SVC_ATTR_STATS, /* nested attribute for service stats */ __IPVS_SVC_ATTR_MAX, }; #define IPVS_SVC_ATTR_MAX (__IPVS_SVC_ATTR_MAX - 1) /* * Attributes used to describe a destination (real server) * * Used inside nested attribute IPVS_CMD_ATTR_DEST */ enum { IPVS_DEST_ATTR_UNSPEC = 0, IPVS_DEST_ATTR_ADDR, /* real server address */ IPVS_DEST_ATTR_PORT, /* real server port */ IPVS_DEST_ATTR_FWD_METHOD, /* forwarding method */ IPVS_DEST_ATTR_WEIGHT, /* destination weight */ IPVS_DEST_ATTR_U_THRESH, /* upper threshold */ IPVS_DEST_ATTR_L_THRESH, /* lower threshold */ IPVS_DEST_ATTR_ACTIVE_CONNS, /* active connections */ IPVS_DEST_ATTR_INACT_CONNS, /* inactive connections */ IPVS_DEST_ATTR_PERSIST_CONNS, /* persistent connections */ IPVS_DEST_ATTR_STATS, /* nested attribute for dest stats */ __IPVS_DEST_ATTR_MAX, }; #define IPVS_DEST_ATTR_MAX (__IPVS_DEST_ATTR_MAX - 1) /* * Attributes describing a sync daemon * * Used inside nested attribute IPVS_CMD_ATTR_DAEMON */ enum { IPVS_DAEMON_ATTR_UNSPEC = 0, IPVS_DAEMON_ATTR_STATE, /* sync daemon state (master/backup) */ IPVS_DAEMON_ATTR_MCAST_IFN, /* multicast interface name */ IPVS_DAEMON_ATTR_SYNC_ID, /* SyncID we belong to */ __IPVS_DAEMON_ATTR_MAX, }; #define IPVS_DAEMON_ATTR_MAX (__IPVS_DAEMON_ATTR_MAX - 1) /* * Attributes used to describe service or destination entry statistics * * Used inside nested attributes IPVS_SVC_ATTR_STATS and IPVS_DEST_ATTR_STATS */ enum { IPVS_STATS_ATTR_UNSPEC = 0, IPVS_STATS_ATTR_CONNS, /* connections scheduled */ IPVS_STATS_ATTR_INPKTS, /* incoming packets */ IPVS_STATS_ATTR_OUTPKTS, /* outgoing packets */ IPVS_STATS_ATTR_INBYTES, /* incoming bytes */ IPVS_STATS_ATTR_OUTBYTES, /* outgoing bytes */ IPVS_STATS_ATTR_CPS, /* current connection rate */ IPVS_STATS_ATTR_INPPS, /* current in packet rate */ IPVS_STATS_ATTR_OUTPPS, /* current out packet rate */ IPVS_STATS_ATTR_INBPS, /* current in byte rate */ IPVS_STATS_ATTR_OUTBPS, /* current out byte rate */ __IPVS_STATS_ATTR_MAX, }; #define IPVS_STATS_ATTR_MAX (__IPVS_STATS_ATTR_MAX - 1) /* Attributes used in response to IPVS_CMD_GET_INFO command */ enum { IPVS_INFO_ATTR_UNSPEC = 0, IPVS_INFO_ATTR_VERSION, /* IPVS version number */ IPVS_INFO_ATTR_CONN_TAB_SIZE, /* size of connection hash table */ __IPVS_INFO_ATTR_MAX, }; #define IPVS_INFO_ATTR_MAX (__IPVS_INFO_ATTR_MAX - 1) #ifdef LIBIPVS_USE_NL extern struct nla_policy ipvs_cmd_policy[IPVS_CMD_ATTR_MAX + 1]; extern struct nla_policy ipvs_service_policy[IPVS_SVC_ATTR_MAX + 1]; extern struct nla_policy ipvs_dest_policy[IPVS_DEST_ATTR_MAX + 1]; extern struct nla_policy ipvs_stats_policy[IPVS_STATS_ATTR_MAX + 1]; extern struct nla_policy ipvs_info_policy[IPVS_INFO_ATTR_MAX + 1]; extern struct nla_policy ipvs_daemon_policy[IPVS_DAEMON_ATTR_MAX + 1]; #endif /* End of Generic Netlink interface definitions */ #undef __u32 #undef __be32 #undef __u16 #undef __be16 #undef __u64 #endif /* _IP_VS_H */ keepalived-1.2.7/keepalived/libipvs-2.6/libipvs.h0000664000175000017500000000743212013300170021346 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 #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 one IPVS service */ 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 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 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.7/keepalived/check/0000775000175000017500000000000012017252420016631 5ustar acassenacassenkeepalived-1.2.7/keepalived/check/check_api.c0000664000175000017500000001335512012246161020712 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]:%d" , inet_sockaddrtos(&checker->rs->addr) , ntohs(inet_sockaddrport(&checker->rs->addr))); (*checker->dump_func) (checker); } /* Queue a checker into the checkers_queue */ void queue_checker(void (*free_func) (void *), void (*dump_func) (void *) , int (*launch) (thread_t *) , void *data) { virtual_server *vs = LIST_TAIL_DATA(check_data->vs); real_server *rs = LIST_TAIL_DATA(vs->rs); checker_t *checker = (checker_t *) MALLOC(sizeof (checker_t)); checker->free_func = free_func; checker->dump_func = dump_func; checker->launch = launch; checker->vs = vs; checker->rs = rs; checker->data = data; checker->id = ncheckers++; checker->enabled = (vs->vfwmark) ? 1 : 0; #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 *vs = LIST_TAIL_DATA(check_data->vs); real_server *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; } } /* 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; for (e = LIST_HEAD(checkers_queue); e; ELEMENT_NEXT(e)) { checker = ELEMENT_DATA(e); log_message(LOG_INFO, "Activating healthchecker for service [%s]:%d" , inet_sockaddrtos(&checker->rs->addr) , ntohs(inet_sockaddrport(&checker->rs->addr))); CHECKER_ENABLE(checker); if (checker->launch) thread_add_timer(master, checker->launch, checker, BOOTSTRAP_DELAY); } } /* 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]:%d" , inet_sockaddrtos(&checker->rs->addr) , ntohs(inet_sockaddrport(&checker->rs->addr))); if (CHECKER_ENABLED(checker) && !enable) log_message(LOG_INFO, "Suspending healthchecker for service [%s]:%d" , inet_sockaddrtos(&checker->rs->addr) , ntohs(inet_sockaddrport(&checker->rs->addr))); 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.7/keepalived/check/check_parser.c0000664000175000017500000002164012017240230021425 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 *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 *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 *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 *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 *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 *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 *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 *vs = LIST_TAIL_DATA(check_data->vs); vs->ha_suspend = 1; } static void virtualhost_handler(vector_t *strvec) { virtual_server *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)); } /* 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 *vs = LIST_TAIL_DATA(check_data->vs); real_server *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 *vs = LIST_TAIL_DATA(check_data->vs); real_server *rs = LIST_TAIL_DATA(vs->rs); rs->u_threshold = atoi(vector_slot(strvec, 1)); } static void lthreshold_handler(vector_t *strvec) { virtual_server *vs = LIST_TAIL_DATA(check_data->vs); real_server *rs = LIST_TAIL_DATA(vs->rs); rs->l_threshold = atoi(vector_slot(strvec, 1)); } #endif static void inhibit_handler(vector_t *strvec) { virtual_server *vs = LIST_TAIL_DATA(check_data->vs); real_server *rs = LIST_TAIL_DATA(vs->rs); rs->inhibit = 1; } static void notify_up_handler(vector_t *strvec) { virtual_server *vs = LIST_TAIL_DATA(check_data->vs); real_server *rs = LIST_TAIL_DATA(vs->rs); rs->notify_up = set_value(strvec); } static void notify_down_handler(vector_t *strvec) { virtual_server *vs = LIST_TAIL_DATA(check_data->vs); real_server *rs = LIST_TAIL_DATA(vs->rs); rs->notify_down = set_value(strvec); } static void alpha_handler(vector_t *strvec) { virtual_server *vs = LIST_TAIL_DATA(check_data->vs); vs->alpha = 1; vs->quorum_state = DOWN; } static void omega_handler(vector_t *strvec) { virtual_server *vs = LIST_TAIL_DATA(check_data->vs); vs->omega = 1; } static void quorum_up_handler(vector_t *strvec) { virtual_server *vs = LIST_TAIL_DATA(check_data->vs); vs->quorum_up = set_value(strvec); } static void quorum_down_handler(vector_t *strvec) { virtual_server *vs = LIST_TAIL_DATA(check_data->vs); vs->quorum_down = set_value(strvec); } static void quorum_handler(vector_t *strvec) { virtual_server *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 *vs = LIST_TAIL_DATA(check_data->vs); long tmp = atol (vector_slot(strvec, 1)); if (tmp < 0 || tmp >= vs->quorum) { log_message(LOG_ERR, "Condition not met: 0 <= Hysteresis <= Quorum - 1"); log_message(LOG_ERR, "Ignoring requested value %s, using 0 instead", (char *) vector_slot(strvec, 1)); log_message(LOG_ERR, "Hint: try defining hysteresis after quorum"); 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("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("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.7/keepalived/check/ipwrapper.c0000664000175000017500000004527212012246161021020 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 /* Returns the sum of all RS weight in a virtual server. */ long unsigned weigh_live_realservers(virtual_server * vs) { element e; real_server *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 * vs, list l) { element e; real_server *rs; char rsip[INET6_ADDRSTRLEN]; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { rs = ELEMENT_DATA(e); if (ISALIVE(rs)) { 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]:%d in VS [%s]:%d" , rs->notify_down , inet_sockaddrtos2(&rs->addr, rsip) , ntohs(inet_sockaddrport(&rs->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); 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. */ if (vs->quorum_state == UP && weigh_live_realservers(vs) < vs->quorum - vs->hysteresis) { vs->quorum_state = DOWN; if (vs->quorum_down) { log_message(LOG_INFO, "Executing [%s] for VS [%s]:%d" , vs->quorum_down , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); 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 * 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 *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 * vs) { element e; real_server *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) { 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 * 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->quorum_state = DOWN; if (!init_service_rs(vs)) return 0; } return 1; } /* Set IPVS rules */ int init_services(void) { element e; list l = check_data->vs; virtual_server *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 *vs, int add) { element e; real_server *rs; if (LIST_ISEMPTY(vs->rs)) return; log_message(LOG_INFO, "%s the pool for VS [%s]:%d" , add?"Adding alive servers to":"Removing alive servers from" , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); 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 */ void update_quorum_state(virtual_server * vs) { char rsip[INET6_ADDRSTRLEN]; /* If we have just gained quorum, it's time to consider notify_up. */ if (vs->quorum_state == DOWN && weigh_live_realservers(vs) >= vs->quorum + vs->hysteresis) { vs->quorum_state = UP; log_message(LOG_INFO, "Gained quorum %lu+%lu=%lu <= %u for VS [%s]:%d" , vs->quorum , vs->hysteresis , vs->quorum + vs->hysteresis , weigh_live_realservers(vs) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); if (vs->s_svr && ISALIVE(vs->s_svr)) { log_message(LOG_INFO, "Removing sorry server [%s]:%d from VS [%s]:%d" , inet_sockaddrtos2(&vs->s_svr->addr, rsip) , ntohs(inet_sockaddrport(&vs->s_svr->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); 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]:%d" , vs->quorum_up , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); 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 && weigh_live_realservers(vs) < vs->quorum - vs->hysteresis) { vs->quorum_state = DOWN; log_message(LOG_INFO, "Lost quorum %lu-%lu=%lu > %u for VS [%s]:%d" , vs->quorum , vs->hysteresis , vs->quorum - vs->hysteresis , weigh_live_realservers(vs) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); if (vs->quorum_down) { log_message(LOG_INFO, "Executing [%s] for VS [%s]:%d" , vs->quorum_down , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); notify_exec(vs->quorum_down); } if (vs->s_svr) { log_message(LOG_INFO, "Adding sorry server [%s]:%d to VS [%s]:%d" , inet_sockaddrtos2(&vs->s_svr->addr, rsip) , ntohs(inet_sockaddrport(&vs->s_svr->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); /* 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 * vs, real_server * rs) { char rsip[INET6_ADDRSTRLEN]; /* * | 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]:%d to VS [%s]:%d" , (rs->inhibit) ? "Enabling" : "Adding" , inet_sockaddrtos2(&rs->addr, rsip) , ntohs(inet_sockaddrport(&rs->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); /* 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]:%d in VS [%s]:%d" , rs->notify_up , inet_sockaddrtos2(&rs->addr, rsip) , ntohs(inet_sockaddrport(&rs->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); 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]:%d from VS [%s]:%d" , (rs->inhibit) ? "Disabling" : "Removing" , inet_sockaddrtos2(&rs->addr, rsip) , ntohs(inet_sockaddrport(&rs->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); /* 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]:%d in VS [%s]:%d" , rs->notify_down , inet_sockaddrtos2(&rs->addr, rsip) , ntohs(inet_sockaddrport(&rs->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); 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 * vs, real_server * rs) { char rsip[INET6_ADDRSTRLEN]; if (weight != rs->weight) { log_message(LOG_INFO, "Changing weight from %d to %d for %s service [%s]:%d of VS [%s]:%d" , rs->weight , weight , ISALIVE(rs) ? "active" : "inactive" , inet_sockaddrtos2(&rs->addr, rsip) , ntohs(inet_sockaddrport(&rs->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); 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 *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 *vs, real_server *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 *vsg_entry, list l) { element e; virtual_server_group_entry *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 * old_vs) { virtual_server_group_entry *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 * old_vs) { virtual_server_group *old; virtual_server_group *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 */ static int vs_exist(virtual_server * old_vs) { element e; list l = check_data->vs; virtual_server *vs; virtual_server_group *vsg; if (LIST_ISEMPTY(l)) return 0; 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 0; else if (!clear_diff_vsg(old_vs)) return 0; } /* * Exist so set alive. */ SET_ALIVE(vs); return 1; } } return 0; } /* Check if rs is in new vs data */ static int rs_exist(real_server * old_rs, list l) { element e; real_server *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 * vs) { element e; list l = check_data->vs; virtual_server *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(virtual_server * old_vs) { element e; list l = old_vs->rs; list new = get_rs_list(old_vs); real_server *rs; char rsip[INET6_ADDRSTRLEN]; /* If old vs didn't own rs then nothing return */ if (LIST_ISEMPTY(l)) return 1; 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]:%d no longer exist" , inet_sockaddrtos(&rs->addr) , ntohs(inet_sockaddrport(&rs->addr))); log_message(LOG_INFO, "Removing service [%s]:%d from VS [%s]:%d" , inet_sockaddrtos2(&rs->addr, rsip) , ntohs(inet_sockaddrport(&rs->addr)) , (old_vs->vsgname) ? old_vs->vsgname : inet_sockaddrtos(&old_vs->addr) , ntohs(inet_sockaddrport(&old_vs->addr))); rs->inhibit = 0; if (!ipvs_cmd(LVS_CMD_DEL_DEST, check_data->vs_group, old_vs, rs)) return 0; } } return 1; } /* When reloading configuration, remove negative diff entries */ int clear_diff_services(void) { element e; list l = old_check_data->vs; virtual_server *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]:%d" , inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); /* Clear VS entry */ if (!clear_service_vs(old_check_data->vs_group, vs)) return 0; } else { /* If vs exist, perform rs pool diff */ if (!clear_diff_rs(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; } keepalived-1.2.7/keepalived/check/check_ssl.c0000664000175000017500000001755212017240230020741 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->keyfile) if (! (SSL_CTX_use_certificate_chain_file (ssl->ctx, check_data->ssl->keyfile))) { 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_arg_t *http_arg = HTTP_ARG(http_get_check); request_t *req = HTTP_REQ(http_arg); 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_arg_t *http_arg = HTTP_ARG(http_get_check); request_t *req = HTTP_REQ(http_arg); 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, http_get_check->connection_to); } 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, http_get_check->connection_to); } 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.7/keepalived/check/ipvswrapper.c0000664000175000017500000006120712012246161021365 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 * ipvs_get_group_by_name(char *gname, list l) { element e; virtual_server_group *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 *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 * rs, char * vsgname) { virtual_server_group *vsg = ipvs_get_group_by_name(vsgname, vs_group); virtual_server_group_entry *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 * vs, real_server * 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]:%d illegal timeout." , inet_ntop2(inet_sockaddrip4(&vs->addr)) , ntohs(inet_sockaddrport(&vs->addr))); 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 * vs, real_server * 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 *vs, virtual_server_group_entry *vsge) { real_server *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 *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 * rs, virtual_server * vs) { virtual_server_group *vsg = ipvs_get_group_by_name(vs->vsgname, vs_group); virtual_server_group_entry *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 *)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 * vs, real_server * 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]:%d illegal timeout." , inet_ntop2(inet_sockaddrip4(&vs->addr)) , ntohs(inet_sockaddrport(&vs->addr))); if (srule->timeout != 0 || vs->granularity_persistence) srule->flags = IP_VS_SVC_F_PERSISTENT; 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 * vs, real_server * 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 *)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 *vs, virtual_server_group_entry *vsge) { real_server *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 *vs) { element e, ge = NULL; real_server *rs; virtual_server_group *vsg = NULL; virtual_server_group_entry *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.7/keepalived/check/check_http.c0000664000175000017500000006303112017240230021110 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(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"); log_message(LOG_INFO, " Connection port = %d", ntohs(inet_sockaddrport(&http_get_chk->dst))); if (http_get_chk->bindto.ss_family) log_message(LOG_INFO, " Bind to = %s", inet_sockaddrtos(&http_get_chk->bindto)); log_message(LOG_INFO, " Connection timeout = %lu", http_get_chk->connection_to/TIMER_HZ); 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_arg_t *) MALLOC(sizeof (http_arg_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->connection_to = 5 * TIMER_HZ; 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); checker_set_dst(&http_get_chk->dst); queue_checker(free_http_get_check, dump_http_get_check, http_connect_thread, http_get_chk); } void connect_p_handler(vector_t *strvec) { http_checker_t *http_get_chk = CHECKER_GET(); checker_set_dst_port(&http_get_chk->dst, htons(CHECKER_VALUE_INT(strvec))); } void bindto_handler(vector_t *strvec) { http_checker_t *http_get_chk = CHECKER_GET(); inet_stosockaddr(vector_slot(strvec, 1), 0, &http_get_chk->bindto); } void connect_to_handler(vector_t *strvec) { http_checker_t *http_get_chk = CHECKER_GET(); http_get_chk->connection_to = CHECKER_VALUE_INT(strvec) * TIMER_HZ; if (http_get_chk->connection_to < TIMER_HZ) http_get_chk->connection_to = TIMER_HZ; } 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_keyword("connect_port", &connect_p_handler); install_keyword("bindto", &bindto_handler); install_keyword("connect_timeout", &connect_to_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_keyword("connect_port", &connect_p_handler); install_keyword("bindto", &bindto_handler); install_keyword("connect_timeout", &connect_to_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_arg_t *http_arg = HTTP_ARG(http_get_check); request_t *req = HTTP_REQ(http_arg); long delay = 0; if (method) { http_arg->url_it += t ? t : -http_arg->url_it; http_arg->retry_it += c ? c : -http_arg->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_arg->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]:%d failed after %d retry." , inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst)), http_arg->retry_it); 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_arg->url_it = 0; http_arg->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_arg->url_it == 0 && http_arg->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_arg->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); http_checker_t *http_get_check = CHECKER_ARG(checker); log_message(LOG_INFO, "Timeout %s server [%s]:%d." , debug_msg , inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst))); /* 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_arg_t *http_arg = HTTP_ARG(http_get_check); return list_element(http_get_check->url, http_arg->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_arg_t *http_arg = HTTP_ARG(http_get_check); request_t *req = HTTP_REQ(http_arg); int r, di = 0; char *digest_tmp; url_t *fetched_url = fetch_next_url(http_get_check); /* 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]:%d url(%s)" ", status_code [%d].", inet_sockaddrtos(&http_get_check->dst), ntohs(inet_sockaddrport(&http_get_check->dst)), 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]:%d url(%d) = [%d]." , inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst)) , http_arg->url_it + 1 , req->status_code); /* * We set retry iterator to max value to not retry * when service is already know as die. */ http_arg->retry_it = http_get_check->nb_get_retry; } return epilog(thread, 2, 0, 1); } else { if (!svr_checker_up(checker->id, checker->rs)) log_message(LOG_INFO, "HTTP status code success to [%s]:%d url(%d)." , inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst)) , http_arg->url_it + 1); return epilog(thread, 1, 1, 0) + 1; } } /* 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]:%d url[%s]" ", MD5SUM [%s].", inet_sockaddrtos(&http_get_check->dst), ntohs(inet_sockaddrport(&http_get_check->dst)), 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]:%d url(%d) = [%s]." , inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst)) , http_arg->url_it + 1 , digest_tmp); /* * We set retry iterator to max value to not retry * when service is already know as die. */ http_arg->retry_it = http_get_check->nb_get_retry; } FREE(digest_tmp); return epilog(thread, 2, 0, 1); } else { if (!svr_checker_up(checker->id, checker->rs)) log_message(LOG_INFO, "MD5 digest success to [%s]:%d url(%d)." , inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst)) , http_arg->url_it + 1); FREE(digest_tmp); 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_arg_t *http_arg = HTTP_ARG(http_get_check); request_t *req = HTTP_REQ(http_arg); 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]:%d: %s" , inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst)) , strerror(errno)); thread_add_read(thread->master, http_read_thread, checker, thread->u.fd, http_get_check->connection_to); 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]:%d: %s" , inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst)) , 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, http_get_check->connection_to); } 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_arg_t *http_arg = HTTP_ARG(http_get_check); request_t *req = HTTP_REQ(http_arg); /* 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, http_get_check->connection_to); else thread_add_read(thread->master, http_read_thread, checker, thread->u.fd, http_get_check->connection_to); 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_arg_t *http_arg = HTTP_ARG(http_get_check); request_t *req = HTTP_REQ(http_arg); char *vhost = CHECKER_VHOST(checker); 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); snprintf(str_request, GET_BUFFER_LENGTH, REQUEST_TEMPLATE, fetched_url->path, (vhost) ? vhost : inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst))); DBG("Processing url(%d) of [%s]:%d.", http_arg->url_it + 1 , inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst))); /* 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]:%d." , inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst))); /* 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, http_get_check->connection_to); 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_arg_t *http_arg = HTTP_ARG(http_get_check); #ifdef _DEBUG_ request_t *req = HTTP_REQ(http_arg); #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]:%d." , inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst))); 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_arg->req) { http_arg->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_arg->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]:%d connected." , inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst))); thread_add_write(thread->master, http_request_thread, checker, thread->u.fd, http_get_check->connection_to); } else { DBG("Connection trouble to: [%s]:%d." , inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst))); #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]:%d." , SSL_get_error (http_arg->req->ssl, ret) , inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst))); 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_arg_t *http_arg = HTTP_ARG(http_get_check); 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]:%d succeed on service." , inet_sockaddrtos(&http_get_check->dst) , ntohs(inet_sockaddrport(&http_get_check->dst))); smtp_alert(checker->rs, NULL, NULL, "UP", "=> CHECK succeed on service <="); update_svr_checker_state(UP, checker->id , checker->vs , checker->rs); } http_arg->req = NULL; return epilog(thread, 1, 0, 0) + 1; } /* Create the socket */ if ((fd = socket(http_get_check->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, &http_get_check->dst, &http_get_check->bindto); /* handle tcp connection status & register check worker thread */ if(tcp_connection_state(fd, status, thread, http_check_thread, http_get_check->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.7/keepalived/check/check_smtp.c0000664000175000017500000006220512017240230021116 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) { smtp_host_t *smtp_host = data; log_message(LOG_INFO, " Checked ip = %s", inet_sockaddrtos(&smtp_host->dst)); log_message(LOG_INFO, " port = %d", ntohs(inet_sockaddrport(&smtp_host->dst))); if (smtp_host->bindto.ss_family) log_message(LOG_INFO, " bindto = %s", inet_sockaddrtos(&smtp_host->bindto)); } /* * 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; /* 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)); 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) */ queue_checker(free_smtp_check, dump_smtp_check, smtp_connect_thread, smtp_checker); /* * 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()); } /* "connect_ip" keyword */ void smtp_ip_handler(vector_t *strvec) { smtp_checker_t *smtp_checker = CHECKER_GET(); smtp_host_t *smtp_host = LIST_TAIL_DATA(smtp_checker->host); inet_stosockaddr(vector_slot(strvec, 1), NULL, &smtp_host->dst); } /* "connect_port" keyword */ void smtp_port_handler(vector_t *strvec) { smtp_checker_t *smtp_checker = CHECKER_GET(); smtp_host_t *smtp_host = LIST_TAIL_DATA(smtp_checker->host); checker_set_dst_port(&smtp_host->dst, htons(CHECKER_VALUE_INT(strvec))); } /* "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; } /* "bindto" keyword */ void smtp_bindto_handler(vector_t *strvec) { smtp_checker_t *smtp_checker = CHECKER_GET(); smtp_host_t *smtp_host = LIST_TAIL_DATA(smtp_checker->host); inet_stosockaddr(vector_slot(strvec, 1), 0, &smtp_host->bindto); } /* 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); install_keyword("connect_timeout", &smtp_timeout_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_keyword("connect_ip", &smtp_ip_handler); install_keyword("connect_port", &smtp_port_handler); install_keyword("bindto", &smtp_bindto_handler); 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]:%d" , inet_sockaddrtos(&smtp_host->dst) , ntohs(inet_sockaddrport(&smtp_host->dst))); 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]:%d. " "Increase SMTP_BUFF_MAX in smtp_check.h" , inet_sockaddrtos(&smtp_host->dst) , ntohs(inet_sockaddrport(&smtp_host->dst))); 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_checker->timeout); 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]:%d < %s" , inet_sockaddrtos(&smtp_host->dst) , ntohs(inet_sockaddrport(&smtp_host->dst)) , 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]:%d" , inet_sockaddrtos(&smtp_host->dst) , ntohs(inet_sockaddrport(&smtp_host->dst))); 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_checker->timeout); 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); /* 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_checker->timeout); 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]:%d" , inet_sockaddrtos(&smtp_host->dst) , ntohs(inet_sockaddrport(&smtp_host->dst))); 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_checker->timeout); fcntl(thread->u.fd, F_SETFL, f); return 0; } /* restore descriptor flags */ fcntl(thread->u.fd, F_SETFL, f); DBG("SMTP_CHECK [%s]:%d > %s" , inet_sockaddrtos(&smtp_host->dst) , ntohs(inet_sockaddrport(&smtp_host->dst)) , 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]:%d" , inet_sockaddrtos(&smtp_host->dst) , ntohs(inet_sockaddrport(&smtp_host->dst))); 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_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_checker->timeout); 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]:%d" , inet_sockaddrtos(&smtp_host->dst) , ntohs(inet_sockaddrport(&smtp_host->dst))); 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]:%d" , inet_sockaddrtos(&smtp_host->dst) , ntohs(inet_sockaddrport(&smtp_host->dst))); 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]:%d" , inet_sockaddrtos(&smtp_host->dst) , ntohs(inet_sockaddrport(&smtp_host->dst))); return 0; break; case connect_timeout: smtp_final(thread, 1, "Connection timeout to server [%s]:%d" , inet_sockaddrtos(&smtp_host->dst) , ntohs(inet_sockaddrport(&smtp_host->dst))); return 0; break; case connect_success: DBG("SMTP_CHECK Remote SMTP server [%s]:%d connected" , inet_sockaddrtos(&smtp_host->dst) , ntohs(inet_sockaddrport(&smtp_host->dst))); /* 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]:%d" , inet_sockaddrtos(&smtp_host->dst) , ntohs(inet_sockaddrport(&smtp_host->dst))); 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]:%d succeed on service." , inet_sockaddrtos(&checker->rs->addr) , ntohs(inet_sockaddrport(&checker->rs->addr))); 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->dst, &smtp_host->bindto); /* handle tcp connection status & register callback the next setp in the process */ if(tcp_connection_state(sd, status, thread, smtp_check_thread, smtp_checker->timeout)) { 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.7/keepalived/check/Makefile.in0000664000175000017500000000602612012246161020702 0ustar acassenacassen# Makefile # # Keepalived OpenSource project. # # Copyright (C) 2001-2012 Alexandre Cassen, KERNEL = @KERN@ CC = @CC@ SNMP_FLAG = @SNMP_SUPPORT@ INCLUDES = -I../include -I../../lib CFLAGS = @CFLAGS@ @CPPFLAGS@ $(INCLUDES) \ -Wall -Wunused -Wstrict-prototypes DEFS = -D$(KERNEL) -D@IPVS_SUPPORT@ -D@IPVS_SYNCD@ -D@VRRP_SUPPORT@ -D@SNMP_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.7/keepalived/check/check_misc.c0000664000175000017500000001625712017240230021074 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); } 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_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.7/keepalived/check/check_data.c0000664000175000017500000002232712017240230021045 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_conf_data *check_data = NULL; check_conf_data *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 *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 *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 *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 *new; new = (virtual_server_group *) MALLOC(sizeof (virtual_server_group)); 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 *vsg = LIST_TAIL_DATA(check_data->vs_group); virtual_server_group_entry *new; new = (virtual_server_group_entry *) MALLOC(sizeof (virtual_server_group_entry)); 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 *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 *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]:%d" , inet_sockaddrtos(&vs->s_svr->addr) , ntohs(inet_sockaddrport(&vs->s_svr->addr))); } if (!LIST_ISEMPTY(vs->rs)) dump_list(vs->rs); } void alloc_vs(char *ip, char *port) { int size = strlen(port); virtual_server *new; new = (virtual_server *) MALLOC(sizeof (virtual_server)); 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 *vs = LIST_TAIL_DATA(check_data->vs); vs->s_svr = (real_server *) MALLOC(sizeof (real_server)); 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 *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 *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 *vs = LIST_TAIL_DATA(check_data->vs); real_server *new; new = (real_server *) MALLOC(sizeof (real_server)); 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_conf_data * alloc_check_data(void) { check_conf_data *new; new = (check_conf_data *) MALLOC(sizeof (check_conf_data)); new->vs = alloc_list(free_vs, dump_vs); new->vs_group = alloc_list(free_vsg, dump_vsg); return new; } void free_check_data(check_conf_data *data) { free_list(data->vs); free_list(data->vs_group); FREE(data); } void dump_check_data(check_conf_data *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(); } keepalived-1.2.7/keepalived/check/check_snmp.c0000664000175000017500000010217312017240230021107 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 *g; if ((g = (virtual_server_group *) 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 *group; virtual_server_group_entry *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 *v; element e; if ((v = (virtual_server *) 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_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 *)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 *vs = NULL; real_server *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 *e = NULL, *be = NULL; element e1, e2 = NULL; virtual_server *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_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 *rs, virtual_server *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 *)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 *vs) { check_snmp_rs_trap(NULL, vs); } keepalived-1.2.7/keepalived/check/check_tcp.c0000664000175000017500000001236112017240230020717 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) { tcp_checker_t *tcp_chk = CHECKER_DATA(data); FREE(tcp_chk); FREE(data); } void dump_tcp_check(void *data) { tcp_checker_t *tcp_chk = CHECKER_DATA(data); log_message(LOG_INFO, " Keepalive method = TCP_CHECK"); log_message(LOG_INFO, " Connection port = %d", ntohs(inet_sockaddrport(&tcp_chk->dst))); if (tcp_chk->bindto.ss_family) log_message(LOG_INFO, " Bind to = %s", inet_sockaddrtos(&tcp_chk->bindto)); log_message(LOG_INFO, " Connection timeout = %d", tcp_chk->connection_to/TIMER_HZ); } void tcp_check_handler(vector_t *strvec) { tcp_checker_t *tcp_chk = (tcp_checker_t *) MALLOC(sizeof (tcp_checker_t)); /* queue new checker */ checker_set_dst(&tcp_chk->dst); queue_checker(free_tcp_check, dump_tcp_check, tcp_connect_thread, tcp_chk); } void connect_port_handler(vector_t *strvec) { tcp_checker_t *tcp_chk = CHECKER_GET(); checker_set_dst_port(&tcp_chk->dst, htons(CHECKER_VALUE_INT(strvec))); } void bind_handler(vector_t *strvec) { tcp_checker_t *tcp_chk = CHECKER_GET(); inet_stosockaddr(vector_slot(strvec, 1), 0, &tcp_chk->bindto); } void connect_timeout_handler(vector_t *strvec) { tcp_checker_t *tcp_chk = CHECKER_GET(); tcp_chk->connection_to = CHECKER_VALUE_INT(strvec) * TIMER_HZ; } void install_tcp_check_keyword(void) { install_keyword("TCP_CHECK", &tcp_check_handler); install_sublevel(); install_keyword("connect_port", &connect_port_handler); install_keyword("bindto", &bind_handler); install_keyword("connect_timeout", &connect_timeout_handler); install_sublevel_end(); } int tcp_check_thread(thread_t * thread) { checker_t *checker; tcp_checker_t *tcp_check; int status; checker = THREAD_ARG(thread); tcp_check = CHECKER_ARG(checker); 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]:%d success." , inet_sockaddrtos(&tcp_check->dst) , ntohs(inet_sockaddrport(&tcp_check->dst))); 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]:%d failed !!!" , inet_sockaddrtos(&tcp_check->dst) , ntohs(inet_sockaddrport(&tcp_check->dst))); 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); tcp_checker_t *tcp_check = CHECKER_ARG(checker); 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(tcp_check->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, &tcp_check->dst, &tcp_check->bindto); /* handle tcp connection status & register check worker thread */ if(tcp_connection_state(fd, status, thread, tcp_check_thread, tcp_check->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.7/keepalived/check/check_daemon.c0000664000175000017500000001474212013300170021375 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 */ ipvs_start(); 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(); /* 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; /* 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 */ log_message(LOG_ALERT, "Healthcheck child process(%d) died: Respawning", pid); start_check_child(); 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.7/keepalived/libipvs-2.4/0000775000175000017500000000000012013300170017515 5ustar acassenacassenkeepalived-1.2.7/keepalived/libipvs-2.4/libipvs.c0000664000175000017500000001271112013300170021333 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.7/keepalived/libipvs-2.4/Makefile.in0000664000175000017500000000036212001611314021565 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.7/keepalived/libipvs-2.4/libipvs.h0000664000175000017500000000350012013300170021334 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.7/configure.in0000664000175000017500000002313212012246161015755 0ustar acassenacassen# # Keepalived OpenSource project. # # Configuration template file for keepalived. # autoconf will generate & check deps for proper compilation # # Copyright (C) 2001-2009 Alexandre Cassen, 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 keepalived/include/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(snmp, [ --enable-snmp compile with SNMP 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(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(popt, poptGetContext,,AC_MSG_ERROR([Popt libraries is required])) AC_CHECK_LIB(nl, nl_socket_modify_cb, [ USE_NL="LIBIPVS_USE_NL" LIBS="$LIBS -lnl" ], [ 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 ----[ 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 < 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.7/AUTHOR0000664000175000017500000000005112001611314014356 0ustar acassenacassenAlexandre Cassen, keepalived-1.2.7/Makefile.in0000664000175000017500000000235312012246161015513 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.7/INSTALL0000664000175000017500000000310112001611314014461 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.7/lib/0000775000175000017500000000000012017252420014211 5ustar acassenacassenkeepalived-1.2.7/lib/scheduler.h0000664000175000017500000000765112017240230016345 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: 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 _SCHEDULER_H #define _SCHEDULER_H /* system includes */ #include #include #include #include #include #include #include #include "timer.h" /* Thread itself. */ typedef struct _thread { unsigned long id; unsigned char type; /* thread type */ struct _thread *next; /* next pointer of the thread */ struct _thread *prev; /* previous pointer of the thread */ struct _thread_master *master; /* pointer to the struct thread_master. */ int (*func) (struct _thread *); /* event function */ void *arg; /* event argument */ timeval_t sands; /* rest of time sands value. */ union { int val; /* second argument of the event. */ int fd; /* file descriptor in case of read/write. */ struct { pid_t pid; /* process id a child thread is wanting. */ int status; /* return status of the process */ } c; } u; } thread_t; /* Linked list of thread. */ typedef struct _thread_list { thread_t *head; thread_t *tail; int count; } thread_list_t; /* Master of the theads. */ typedef struct _thread_master { thread_list_t read; thread_list_t write; thread_list_t timer; thread_list_t child; thread_list_t event; thread_list_t ready; thread_list_t unuse; fd_set readfd; fd_set writefd; fd_set exceptfd; unsigned long alloc; } thread_master_t; /* Thread types. */ #define THREAD_READ 0 #define THREAD_WRITE 1 #define THREAD_TIMER 2 #define THREAD_EVENT 3 #define THREAD_CHILD 4 #define THREAD_READY 5 #define THREAD_UNUSED 6 #define THREAD_WRITE_TIMEOUT 7 #define THREAD_READ_TIMEOUT 8 #define THREAD_CHILD_TIMEOUT 9 #define THREAD_TERMINATE 10 #define THREAD_READY_FD 11 /* MICRO SEC def */ #define BOOTSTRAP_DELAY TIMER_HZ #define RESPAWN_TIMER 60*TIMER_HZ /* Macros. */ #define THREAD_ARG(X) ((X)->arg) #define THREAD_FD(X) ((X)->u.fd) #define THREAD_VAL(X) ((X)->u.val) #define THREAD_CHILD_PID(X) ((X)->u.c.pid) #define THREAD_CHILD_STATUS(X) ((X)->u.c.status) /* global vars exported */ extern thread_master_t *master; /* Prototypes. */ extern thread_master_t *thread_make_master(void); extern thread_t *thread_add_terminate_event(thread_master_t *); extern void thread_destroy_master(thread_master_t *); extern thread_t *thread_add_read(thread_master_t *, int (*func) (thread_t *), void *, int, long); extern thread_t *thread_add_write(thread_master_t *, int (*func) (thread_t *), void *, int, long); extern thread_t *thread_add_timer(thread_master_t *, int (*func) (thread_t *), void *, long); extern thread_t *thread_add_child(thread_master_t *, int (*func) (thread_t *), void *, pid_t, long); extern thread_t *thread_add_event(thread_master_t *, int (*func) (thread_t *), void *, int); extern void thread_cancel(thread_t *); extern void thread_cancel_event(thread_master_t *, void *); extern thread_t *thread_fetch(thread_master_t *, thread_t *); extern void thread_child_handler(void *, int); extern void thread_call(thread_t *); extern void launch_scheduler(void); #endif keepalived-1.2.7/lib/html.c0000664000175000017500000000472412017240230015324 0ustar acassenacassen/* * Soft: Perform a GET query to a remote HTTP/HTTPS server. * Set a timer to compute global remote server response * time. * * Part: HTML stream parser utility functions. * * 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 "html.h" #include "memory.h" /* Return the http header content length */ int extract_content_length(char *buffer, int size) { char *clen = strstr(buffer, CONTENT_LENGTH); char *content_buffer = NULL; char *buf_len; int inc = 0; int i; /* Allocate the room */ buf_len = (char *)MALLOC(40); /* Pattern not found */ if (!clen) return 0; /* Content-Length extraction */ while (*(clen++) != ':'); content_buffer = clen; while (*(clen++) != '\r' && *clen != '\n') inc++; for (i = 0; i < inc; i++) strncat(buf_len, content_buffer+i, 1); i = atoi(buf_len); FREE(buf_len); return i; } /* * Return the http header error code. According * to rfc2616.6.1 status code is between HTTP_Version * and Reason_Phrase, separated by space caracter. */ int extract_status_code(char *buffer, int size) { char *buf_code; char *begin; char *end = buffer + size; int inc = 0; /* Allocate the room */ buf_code = (char *)MALLOC(10); /* Status-Code extraction */ while (buffer < end && *buffer++ != ' ') ; begin = buffer; while (buffer < end && *buffer++ != ' ') inc++; strncat(buf_code, begin, inc); inc = atoi(buf_code); FREE(buf_code); return inc; } /* simple function returning a pointer to the html buffer begin */ char *extract_html(char *buffer, int size_buffer) { char *end = buffer + size_buffer; char *cur; for (cur = buffer; cur + 3 < end; cur++) if (*cur == '\r' && *(cur+1) == '\n' && *(cur+2) == '\r' && *(cur+3) == '\n') return cur + 4; return NULL; } keepalived-1.2.7/lib/html.h0000664000175000017500000000233112017240230015321 0ustar acassenacassen/* * Soft: Perform a GET query to a remote HTTP/HTTPS server. * Set a timer to compute global remote server response * time. * * Part: parser.c include file. * * 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 _HTML_H #define _HTML_H /* HTTP header tag */ #define CONTENT_LENGTH "Content-Length:" /* Prototypes */ extern int extract_content_length(char *buffer, int size); extern int extract_status_code(char *buffer, int size); extern char *extract_html(char *buffer, int size_buffer); #endif keepalived-1.2.7/lib/memory.c0000664000175000017500000002263712017240230015673 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Memory management framework. This framework is used to * find any memory leak. * * 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 "memory.h" #include "utils.h" /* Global var */ unsigned long mem_allocated; /* Total memory used in Bytes */ void * xalloc(unsigned long size) { void *mem; if ((mem = malloc(size))) mem_allocated += size; return mem; } void * zalloc(unsigned long size) { void *mem; if ((mem = malloc(size))) { memset(mem, 0, size); mem_allocated += size; } return mem; } void xfree(void *p) { mem_allocated -= sizeof (p); free(p); p = NULL; } /* KeepAlived memory management. in debug mode, * help finding eventual memory leak. * Allocation memory types manipulated are : * * +type+--------meaning--------+ * ! 0 ! Free slot ! * ! 1 ! Overrun ! * ! 2 ! free null ! * ! 3 ! realloc null ! * ! 4 ! Not previus allocated ! * ! 8 ! Last free list ! * ! 9 ! Allocated ! * +----+-----------------------+ * * global variabel debug bit 9 ( 512 ) used to * flag some memory error. * */ #ifdef _DEBUG_ typedef struct { int type; int line; char *func; char *file; void *ptr; unsigned long size; long csum; } MEMCHECK; /* Last free pointers */ static MEMCHECK free_list[256]; static MEMCHECK alloc_list[MAX_ALLOC_LIST]; static int number_alloc_list = 0; static int n = 0; /* Alloc list pointer */ static int f = 0; /* Free list pointer */ char * keepalived_malloc(unsigned long size, char *file, char *function, int line) { void *buf; int i = 0; long check; buf = zalloc(size + sizeof (long)); check = 0xa5a5 + size; *(long *) ((char *) buf + size) = check; while (i < number_alloc_list) { if (alloc_list[i].type == 0) break; i++; } if (i == number_alloc_list) number_alloc_list++; assert(number_alloc_list < MAX_ALLOC_LIST); alloc_list[i].ptr = buf; alloc_list[i].size = size; alloc_list[i].file = file; alloc_list[i].func = function; alloc_list[i].line = line; alloc_list[i].csum = check; alloc_list[i].type = 9; if (debug & 1) printf("zalloc[%3d:%3d], %p, %4ld at %s, %3d, %s\n", i, number_alloc_list, buf, size, file, line, function); n++; return buf; } int keepalived_free(void *buffer, char *file, char *function, int line) { int i = 0; void *buf; /* If nullpointer remember */ if (buffer == NULL) { i = number_alloc_list++; assert(number_alloc_list < MAX_ALLOC_LIST); alloc_list[i].ptr = buffer; alloc_list[i].size = 0; alloc_list[i].file = file; alloc_list[i].func = function; alloc_list[i].line = line; alloc_list[i].type = 2; if (debug & 1) printf("free NULL in %s, %3d, %s\n", file, line, function); debug |= 512; /* Memory Error detect */ return n; } else buf = buffer; while (i < number_alloc_list) { if (alloc_list[i].type == 9 && alloc_list[i].ptr == buf) { if (* ((long *) ((char *) alloc_list[i].ptr + alloc_list[i].size)) == alloc_list[i].csum) alloc_list[i].type = 0; /* Release */ else { alloc_list[i].type = 1; /* Overrun */ if (debug & 1) { printf("free corrupt, buffer overrun [%3d:%3d], %p, %4ld at %s, %3d, %s\n", i, number_alloc_list, buf, alloc_list[i].size, file, line, function); dump_buffer(alloc_list[i].ptr, alloc_list[i].size + sizeof (long)); printf("Check_sum\n"); dump_buffer((char *) &alloc_list[i].csum, sizeof(long)); debug |= 512; /* Memory Error detect */ } } break; } i++; } /* Not found */ if (i == number_alloc_list) { printf("Free ERROR %p\n", buffer); number_alloc_list++; assert(number_alloc_list < MAX_ALLOC_LIST); alloc_list[i].ptr = buf; alloc_list[i].size = 0; alloc_list[i].file = file; alloc_list[i].func = function; alloc_list[i].line = line; alloc_list[i].type = 4; debug |= 512; return n; } if (buffer != NULL) xfree(buffer); if (debug & 1) printf("free [%3d:%3d], %p, %4ld at %s, %3d, %s\n", i, number_alloc_list, buf, alloc_list[i].size, file, line, function); free_list[f].file = file; free_list[f].line = line; free_list[f].func = function; free_list[f].ptr = buffer; free_list[f].type = 8; free_list[f].csum = i; /* Using this field for row id */ f++; f &= 255; n--; return n; } void keepalived_free_final(char *banner) { unsigned int sum = 0, overrun = 0, badptr = 0; int i, j; i = 0; printf("\n---[ Keepalived memory dump for (%s)]---\n\n", banner); while (i < number_alloc_list) { switch (alloc_list[i].type) { case 3: badptr++; printf ("null pointer to realloc(nil,%ld)! at %s, %3d, %s\n", alloc_list[i].size, alloc_list[i].file, alloc_list[i].line, alloc_list[i].func); break; case 4: badptr++; printf ("pointer not found in table to free(%p) [%3d:%3d], at %s, %3d, %s\n", alloc_list[i].ptr, i, number_alloc_list, alloc_list[i].file, alloc_list[i].line, alloc_list[i].func); for (j = 0; j < 256; j++) if (free_list[j].ptr == alloc_list[i].ptr) if (free_list[j].type == 8) printf (" -> pointer allready released at [%3d:%3d], at %s, %3d, %s\n", (int) free_list[j].csum, number_alloc_list, free_list[j].file, free_list[j].line, free_list[j].func); break; case 2: badptr++; printf("null pointer to free(nil)! at %s, %3d, %s\n", alloc_list[i].file, alloc_list[i].line, alloc_list[i].func); break; case 1: overrun++; printf("%p [%3d:%3d], %4ld buffer overrun!:\n", alloc_list[i].ptr, i, number_alloc_list, alloc_list[i].size); printf(" --> source of malloc: %s, %3d, %s\n", alloc_list[i].file, alloc_list[i].line, alloc_list[i].func); break; case 9: sum += alloc_list[i].size; printf("%p [%3d:%3d], %4ld not released!:\n", alloc_list[i].ptr, i, number_alloc_list, alloc_list[i].size); printf(" --> source of malloc: %s, %3d, %s\n", alloc_list[i].file, alloc_list[i].line, alloc_list[i].func); break; } i++; } printf("\n\n---[ Keepalived memory dump summary for (%s) ]---\n", banner); printf("Total number of bytes not freed...: %d\n", sum); printf("Number of entries not freed.......: %d\n", n); printf("Maximum allocated entries.........: %d\n", number_alloc_list); printf("Number of bad entries.............: %d\n", badptr); printf("Number of buffer overrun..........: %d\n\n", overrun); if (sum || n || badptr || overrun) printf("=> Program seems to have some memory problem !!!\n\n"); else printf("=> Program seems to be memory allocation safe...\n\n"); } void * keepalived_realloc(void *buffer, unsigned long size, char *file, char *function, int line) { int i = 0; void *buf, *buf2; long check; if (buffer == NULL) { printf("realloc %p %s, %3d %s\n", buffer, file, line, function); i = number_alloc_list++; assert(number_alloc_list < MAX_ALLOC_LIST); alloc_list[i].ptr = NULL; alloc_list[i].size = 0; alloc_list[i].file = file; alloc_list[i].func = function; alloc_list[i].line = line; alloc_list[i].type = 3; return keepalived_malloc(size, file, function, line); } buf = buffer; while (i < number_alloc_list) { if (alloc_list[i].ptr == buf) { buf = alloc_list[i].ptr; break; } i++; } /* not found */ if (i == number_alloc_list) { printf("realloc ERROR no matching zalloc %p \n", buffer); number_alloc_list++; assert(number_alloc_list < MAX_ALLOC_LIST); alloc_list[i].ptr = buf; alloc_list[i].size = 0; alloc_list[i].file = file; alloc_list[i].func = function; alloc_list[i].line = line; alloc_list[i].type = 9; debug |= 512; /* Memory Error detect */ return NULL; } buf2 = ((char *) buf) + alloc_list[i].size; if (*(long *) (buf2) != alloc_list[i].csum) { alloc_list[i].type = 1; debug |= 512; /* Memory Error detect */ } buf = realloc(buffer, size + sizeof (long)); check = 0xa5a5 + size; *(long *) ((char *) buf + size) = check; alloc_list[i].csum = check; if (debug & 1) printf("realloc [%3d:%3d] %p, %4ld %s %d %s -> %p %4ld %s %d %s\n", i, number_alloc_list, alloc_list[i].ptr, alloc_list[i].size, file, line, function, buf, size, alloc_list[i].file, alloc_list[i].line, alloc_list[i].func); alloc_list[i].ptr = buf; alloc_list[i].size = size; alloc_list[i].file = file; alloc_list[i].line = line; alloc_list[i].func = function; return buf; } #endif keepalived-1.2.7/lib/utils.h0000664000175000017500000000433312017240230015521 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: utils.h 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 _UTILS_H #define _UTILS_H /* system includes */ #include #include #include #include #include #include #include #include #include /* Global debugging logging facilities */ #ifdef _DEBUG_ #define DBG(fmt, msg...) syslog(LOG_DEBUG, fmt, ## msg) #else #define DBG(fmt, msg...) #endif /* global vars exported */ extern int debug; /* Prototypes defs */ extern void dump_buffer(char *, int); extern u_short in_csum(u_short *, int, u_short); extern char *inet_ntop2(uint32_t); extern char *inet_ntoa2(uint32_t, char *); extern uint8_t inet_stom(char *); extern uint8_t inet_stor(char *); extern int inet_stosockaddr(char *, char *, struct sockaddr_storage *); extern char *inet_sockaddrtos(struct sockaddr_storage *); extern char *inet_sockaddrtos2(struct sockaddr_storage *, char *); extern uint16_t inet_sockaddrport(struct sockaddr_storage *); extern uint32_t inet_sockaddrip4(struct sockaddr_storage *); extern int inet_sockaddrip6(struct sockaddr_storage *, struct in6_addr *); extern int inet_ston(const char *, uint32_t *); uint32_t inet_broadcast(uint32_t, uint32_t); uint32_t inet_cidrtomask(uint8_t); extern char *get_local_name(void); #endif keepalived-1.2.7/lib/signals.h0000664000175000017500000000271512017240230016023 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: signals.c include file. * * Author: Kevin Lindsay, * 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 _SIGNALS_H #define _SIGNALS_H /* Prototypes */ extern int signal_pending(void); extern void *signal_set(int signo, void (*func) (void *, int), void *); extern void *signal_ignore(int signo); extern void signal_handler_init(void); extern void signal_handler_destroy(void); extern void signal_reset(void); extern void signal_run_callback(void); extern void signal_wait_handlers(void); extern int signal_rfd(void); #endif keepalived-1.2.7/lib/parser.c0000664000175000017500000002331712017240230015653 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 #include #include #include "parser.h" #include "memory.h" #include "logger.h" /* global vars */ vector_t *keywords; vector_t *current_keywords; FILE *current_stream; char *current_conf_file; int reload = 0; /* local vars */ static int sublevel = 0; void keyword_alloc(vector_t *keywords_vec, char *string, void (*handler) (vector_t *)) { keyword_t *keyword; vector_alloc_slot(keywords_vec); keyword = (keyword_t *) MALLOC(sizeof(keyword_t)); keyword->string = string; keyword->handler = handler; vector_set_slot(keywords_vec, keyword); } void keyword_alloc_sub(vector_t *keywords_vec, char *string, void (*handler) (vector_t *)) { int i = 0; keyword_t *keyword; /* fetch last keyword */ keyword = vector_slot(keywords_vec, vector_size(keywords_vec) - 1); /* position to last sub level */ for (i = 0; i < sublevel; i++) keyword = vector_slot(keyword->sub, vector_size(keyword->sub) - 1); /* First sub level allocation */ if (!keyword->sub) keyword->sub = vector_alloc(); /* add new sub keyword */ keyword_alloc(keyword->sub, string, handler); } /* Exported helpers */ void install_sublevel(void) { sublevel++; } void install_sublevel_end(void) { sublevel--; } void install_keyword_root(char *string, void (*handler) (vector_t *)) { keyword_alloc(keywords, string, handler); } void install_keyword(char *string, void (*handler) (vector_t *)) { keyword_alloc_sub(keywords, string, handler); } void dump_keywords(vector_t *keydump, int level) { int i, j; keyword_t *keyword_vec; for (i = 0; i < vector_size(keydump); i++) { keyword_vec = vector_slot(keydump, i); for (j = 0; j < level; j++) printf(" "); printf("Keyword : %s\n", keyword_vec->string); if (keyword_vec->sub) dump_keywords(keyword_vec->sub, level + 1); } } void free_keywords(vector_t *keywords_vec) { keyword_t *keyword_vec; int i; for (i = 0; i < vector_size(keywords_vec); i++) { keyword_vec = vector_slot(keywords_vec, i); if (keyword_vec->sub) free_keywords(keyword_vec->sub); FREE(keyword_vec); } vector_free(keywords_vec); } vector_t * alloc_strvec(char *string) { char *cp, *start, *token; int str_len; vector_t *strvec; if (!string) return NULL; cp = string; /* Skip white spaces */ while (isspace((int) *cp) && *cp != '\0') cp++; /* Return if there is only white spaces */ if (*cp == '\0') return NULL; /* Return if string begin with a comment */ if (*cp == '!' || *cp == '#') return NULL; /* Create a vector and alloc each command piece */ strvec = vector_alloc(); while (1) { start = cp; if (*cp == '"') { cp++; token = MALLOC(2); *(token) = '"'; *(token + 1) = '\0'; } else { while (!isspace((int) *cp) && *cp != '\0' && *cp != '"') cp++; str_len = cp - start; token = MALLOC(str_len + 1); memcpy(token, start, str_len); *(token + str_len) = '\0'; } /* Alloc & set the slot */ vector_alloc_slot(strvec); vector_set_slot(strvec, token); while (isspace((int) *cp) && *cp != '\0') cp++; if (*cp == '\0' || *cp == '!' || *cp == '#') return strvec; } } void read_conf_file(char *conf_file) { FILE *stream; char *path; int ret; glob_t globbuf; globbuf.gl_offs = 0; glob(conf_file, 0, NULL, &globbuf); int i; for(i = 0; i < globbuf.gl_pathc; i++){ log_message(LOG_INFO, "Opening file '%s'.", globbuf.gl_pathv[i]); stream = fopen(globbuf.gl_pathv[i], "r"); if (!stream) { log_message(LOG_INFO, "Configuration file '%s' open problem (%s)..." , globbuf.gl_pathv[i], strerror(errno)); return; } current_stream = stream; current_conf_file = globbuf.gl_pathv[i]; char prev_path[MAXBUF]; path = getcwd(prev_path, MAXBUF); if (!path) { log_message(LOG_INFO, "getcwd(%s) error (%s)" , prev_path, strerror(errno)); } char *confpath = strdup(globbuf.gl_pathv[i]); dirname(confpath); ret = chdir(confpath); if (ret < 0) { log_message(LOG_INFO, "chdir(%s) error (%s)" , confpath, strerror(errno)); } process_stream(current_keywords); fclose(stream); ret = chdir(prev_path); if (ret < 0) { log_message(LOG_INFO, "chdir(%s) error (%s)" , prev_path, strerror(errno)); } } globfree(&globbuf); } int check_include(char *buf) { char *str; vector_t *strvec; char *path; int ret; strvec = alloc_strvec(buf); if (!strvec){ return 0; } str = vector_slot(strvec, 0); if (!strcmp(str, EOB)) { free_strvec(strvec); return 0; } if(!strcmp("include", str) && vector_size(strvec) == 2){ char *conf_file = vector_slot(strvec, 1); FILE *prev_stream = current_stream; char *prev_conf_file = current_conf_file; char prev_path[MAXBUF]; path = getcwd(prev_path, MAXBUF); if (!path) { log_message(LOG_INFO, "getcwd(%s) error (%s)\n" , prev_path, strerror(errno)); } read_conf_file(conf_file); current_stream = prev_stream; current_conf_file = prev_conf_file; ret = chdir(prev_path); if (ret < 0) { log_message(LOG_INFO, "chdir(%s) error (%s)\n" , prev_path, strerror(errno)); } return 1; } free_strvec(strvec); return 0; } int read_line(char *buf, int size) { int ch; do { int count = 0; memset(buf, 0, MAXBUF); while ((ch = fgetc(current_stream)) != EOF && (int) ch != '\n' && (int) ch != '\r') { if (count < size) buf[count] = (int) ch; else break; count++; } } while (check_include(buf) == 1); return (ch == EOF) ? 0 : 1; } vector_t * read_value_block(void) { char *buf; int i; char *str = NULL; char *dup; vector_t *vec = NULL; vector_t *elements = vector_alloc(); 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)) for (i = 0; i < vector_size(vec); i++) { str = vector_slot(vec, i); dup = (char *) MALLOC(strlen(str) + 1); memcpy(dup, str, strlen(str)); vector_alloc_slot(elements); vector_set_slot(elements, dup); } free_strvec(vec); } memset(buf, 0, MAXBUF); } FREE(buf); return elements; } void alloc_value_block(vector_t *strvec, void (*alloc_func) (vector_t *)) { char *buf; char *str = NULL; vector_t *vec = NULL; 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)) (*alloc_func) (vec); free_strvec(vec); } memset(buf, 0, MAXBUF); } FREE(buf); } void * set_value(vector_t *strvec) { char *str = vector_slot(strvec, 1); int size = strlen(str); int i = 0; int len = 0; char *alloc = NULL; char *tmp; if (*str == '"') { for (i = 2; i < vector_size(strvec); i++) { str = vector_slot(strvec, i); len += strlen(str); if (!alloc) alloc = (char *) MALLOC(sizeof (char *) * (len + 1)); else { alloc = REALLOC(alloc, sizeof (char *) * (len + 1)); tmp = vector_slot(strvec, i-1); if (*str != '"' && *tmp != '"') strncat(alloc, " ", 1); } if (i != vector_size(strvec)-1) strncat(alloc, str, strlen(str)); } } else { alloc = MALLOC(sizeof (char *) * (size + 1)); memcpy(alloc, str, size); } return alloc; } /* recursive configuration stream handler */ static int kw_level = 0; void process_stream(vector_t *keywords_vec) { int i; keyword_t *keyword_vec; char *str; char *buf; vector_t *strvec; vector_t *prev_keywords = current_keywords; current_keywords = keywords_vec; buf = zalloc(MAXBUF); while (read_line(buf, MAXBUF)) { strvec = alloc_strvec(buf); memset(buf,0, MAXBUF); if (!strvec) continue; str = vector_slot(strvec, 0); if (!strcmp(str, EOB) && kw_level > 0) { free_strvec(strvec); break; } for (i = 0; i < vector_size(keywords_vec); i++) { keyword_vec = vector_slot(keywords_vec, i); if (!strcmp(keyword_vec->string, str)) { if (keyword_vec->handler) (*keyword_vec->handler) (strvec); if (keyword_vec->sub) { kw_level++; process_stream(keyword_vec->sub); kw_level--; } break; } } free_strvec(strvec); } current_keywords = prev_keywords; free(buf); return; } /* Data initialization */ void init_data(char *conf_file, vector_t * (*init_keywords) (void)) { /* Init Keywords structure */ keywords = vector_alloc(); (*init_keywords) (); #if 0 /* Dump configuration */ vector_dump(keywords); dump_keywords(keywords, 0); #endif /* Stream handling */ current_keywords = keywords; read_conf_file((conf_file) ? conf_file : CONF); free_keywords(keywords); } keepalived-1.2.7/lib/memory.h0000664000175000017500000000442312017240230015671 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: memory.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 _MEMORY_H #define _MEMORY_H /* system includes */ #include #include #include #include #include /* extern types */ extern unsigned long mem_allocated; extern void *xalloc(unsigned long size); extern void *zalloc(unsigned long size); extern void xfree(void *p); /* Global alloc macro */ #define ALLOC(n) (xalloc(n)) /* Local defines */ #ifdef _DEBUG_ #define MAX_ALLOC_LIST 2048 #define MALLOC(n) ( keepalived_malloc((n), \ (__FILE__), (char *)(__FUNCTION__), (__LINE__)) ) #define FREE(b) ( keepalived_free((b), \ (__FILE__), (char *)(__FUNCTION__), (__LINE__)) ) #define REALLOC(b,n) ( keepalived_realloc((b), (n), \ (__FILE__), (char *)(__FUNCTION__), (__LINE__)) ) /* Memory debug prototypes defs */ extern char *keepalived_malloc(unsigned long, char *, char *, int); extern int keepalived_free(void *, char *, char *, int); extern void *keepalived_realloc(void *, unsigned long, char *, char *, int); extern void keepalived_free_final(char *); #else #define MALLOC(n) (zalloc(n)) #define FREE(p) (xfree(p)) #define REALLOC(p,n) (realloc((p),(n))) #endif /* Common defines */ #define FREE_PTR(P) if((P)) FREE((P)); #endif keepalived-1.2.7/lib/list_head.c0000664000175000017500000000445312017240230016313 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: list_head. This code is comming from Linux Kernel. * * 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 "list_head.h" void list_sort(struct list_head *head, int (*cmp)(struct list_head *a, struct list_head *b)) { struct list_head *p, *q, *e, *list, *tail, *oldhead; int insize, nmerges, psize, qsize, i; list = head->next; list_head_del(head); insize = 1; while (1) { p = oldhead = list; list = tail = NULL; nmerges = 0; while (p) { nmerges++; q = p; psize = 0; for (i = 0; i < insize; i++) { psize++; q = q->next == oldhead ? NULL : q->next; if (!q) break; } qsize = insize; while (psize > 0 || (qsize > 0 && q)) { if (!psize) { e = q; q = q->next; qsize--; if (q == oldhead) q = NULL; } else if (!qsize || !q) { e = p; p = p->next; psize--; if (p == oldhead) p = NULL; } else if (cmp(p, q) <= 0) { e = p; p = p->next; psize--; if (p == oldhead) p = NULL; } else { e = q; q = q->next; qsize--; if (q == oldhead) q = NULL; } if (tail) tail->next = e; else list = e; e->prev = tail; tail = e; } p = q; } tail->next = list; list->prev = tail; if (nmerges <= 1) break; insize *= 2; } head->next = list; head->prev = list->prev; list->prev->next = head; list->prev = head; } keepalived-1.2.7/lib/vector.h0000664000175000017500000000463012017240230015663 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: vector.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 _VECTOR_H #define _VECTOR_H /* vector definition */ typedef struct _vector { unsigned int active; unsigned int allocated; void **slot; } vector_t; /* Some defines */ #define VECTOR_DEFAULT_SIZE 1 /* Some usefull macros */ #define vector_slot(V,E) ((V)->slot[(E)]) #define vector_size(V) ((V)->allocated) #define vector_active(V) ((V)->active) #define vector_foreach_slot(v,p,i) \ for (i = 0; i < (v)->allocated && ((p) = (v)->slot[i]); i++) /* Prototypes */ extern vector_t *vector_alloc(void); extern vector_t *vector_init(unsigned int); extern void vector_alloc_slot(vector_t *); extern void vector_insert_slot(vector_t *, int, void *); extern vector_t *vector_copy(vector_t *); extern void vector_ensure(vector_t *, unsigned int); extern int vector_empty_slot(vector_t *); extern int vector_set(vector_t *, void *); extern void vector_set_slot(vector_t *, void *); extern int vector_set_index(vector_t *, unsigned int, void *); extern void *vector_lookup(vector_t *, unsigned int); extern void *vector_lookup_ensure(vector_t *, unsigned int); extern void vector_unset(vector_t *, unsigned int); extern unsigned int vector_count(vector_t *); extern void vector_only_wrapper_free(vector_t *); extern void vector_only_index_free(void *); extern void vector_only_slot_free(void *); extern void vector_free(vector_t *); extern void vector_dump(vector_t *); extern void free_strvec(vector_t *); extern void dump_strvec(vector_t *); #endif keepalived-1.2.7/lib/logger.h0000664000175000017500000000216012017240230015634 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: logging facility. * * 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 _LOGGER_H #define _LOGGER_H void enable_console_log(void); void log_message(int priority, char* format, ...); #endif keepalived-1.2.7/lib/timer.c0000664000175000017500000001255012017240230015474 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Timer manipulations. * * 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 "timer.h" /* time_now holds current time */ timeval_t time_now = { tv_sec: 0, tv_usec: 0 }; /* set a timer to a specific value */ timeval_t timer_dup(timeval_t b) { timeval_t a; timer_reset(a); a.tv_sec = b.tv_sec; a.tv_usec = b.tv_usec; return a; } /* timer compare */ int timer_cmp(timeval_t a, timeval_t b) { if (a.tv_sec > b.tv_sec) return 1; if (a.tv_sec < b.tv_sec) return -1; if (a.tv_usec > b.tv_usec) return 1; if (a.tv_usec < b.tv_usec) return -1; return 0; } /* timer sub */ timeval_t timer_sub(timeval_t a, timeval_t b) { timeval_t ret; timer_reset(ret); ret.tv_usec = a.tv_usec - b.tv_usec; ret.tv_sec = a.tv_sec - b.tv_sec; if (ret.tv_usec < 0) { ret.tv_usec += TIMER_HZ; ret.tv_sec--; } return ret; } /* timer add */ timeval_t timer_add_long(timeval_t a, long b) { timeval_t ret; timer_reset(ret); ret.tv_usec = a.tv_usec + b % TIMER_HZ; ret.tv_sec = a.tv_sec + b / TIMER_HZ; if (ret.tv_usec >= TIMER_HZ) { ret.tv_sec++; ret.tv_usec -= TIMER_HZ; } return ret; } /* This function is a wrapper for gettimeofday(). It uses local storage to * guarantee that the returned time will always be monotonic. If the time goes * backwards, it returns the same as previous one and readjust its internal * drift. If the time goes forward further than TIME_MAX_FORWARD_US * microseconds since last call, it will bound it to that value. It is designed * to be used as a drop-in replacement of gettimeofday(&now, NULL). It will * normally return 0, unless is NULL, in which case it will return -1 and * set errno to EFAULT. */ int monotonic_gettimeofday(timeval_t *now) { static timeval_t mono_date; static timeval_t drift; /* warning: signed seconds! */ timeval_t sys_date, adjusted, deadline; if (!now) { errno = EFAULT; return -1; } gettimeofday(&sys_date, NULL); /* on first call, we set mono_date to system date */ if (mono_date.tv_sec == 0) { mono_date = sys_date; drift.tv_sec = drift.tv_usec = 0; *now = mono_date; return 0; } /* compute new adjusted time by adding the drift offset */ adjusted.tv_sec = sys_date.tv_sec + drift.tv_sec; adjusted.tv_usec = sys_date.tv_usec + drift.tv_usec; if (adjusted.tv_usec >= TIMER_HZ) { adjusted.tv_usec -= TIMER_HZ; adjusted.tv_sec++; } /* check for jumps in the past, and bound to last date */ if (adjusted.tv_sec < mono_date.tv_sec || (adjusted.tv_sec == mono_date.tv_sec && adjusted.tv_usec < mono_date.tv_usec)) goto fixup; /* check for jumps too far in the future, and bound them to * TIME_MAX_FORWARD_US microseconds. */ deadline.tv_sec = mono_date.tv_sec + TIME_MAX_FORWARD_US / TIMER_HZ; deadline.tv_usec = mono_date.tv_usec + TIME_MAX_FORWARD_US % TIMER_HZ; if (deadline.tv_usec >= TIMER_HZ) { deadline.tv_usec -= TIMER_HZ; deadline.tv_sec++; } if (adjusted.tv_sec > deadline.tv_sec || (adjusted.tv_sec == deadline.tv_sec && adjusted.tv_usec >= deadline.tv_usec)) { mono_date = deadline; goto fixup; } /* adjusted date is correct */ mono_date = adjusted; *now = mono_date; return 0; fixup: /* Now we have to recompute the drift between sys_date and * mono_date. Since it can be negative and we don't want to * play with negative carries in all computations, we take * care of always having the microseconds positive. */ drift.tv_sec = mono_date.tv_sec - sys_date.tv_sec; drift.tv_usec = mono_date.tv_usec - sys_date.tv_usec; if (drift.tv_usec < 0) { drift.tv_usec += TIMER_HZ; drift.tv_sec--; } *now = mono_date; return 0; } /* current time */ timeval_t timer_now(void) { timeval_t curr_time; int old_errno = errno; /* init timer */ timer_reset(curr_time); monotonic_gettimeofday(&curr_time); errno = old_errno; return curr_time; } /* sets and returns current time from system time */ timeval_t set_time_now(void) { int old_errno = errno; /* init timer */ timer_reset(time_now); monotonic_gettimeofday(&time_now); errno = old_errno; return time_now; } /* timer sub from current time */ timeval_t timer_sub_now(timeval_t a) { return timer_sub(time_now, a); } /* print timer value */ void timer_dump(timeval_t a) { unsigned long timer; timer = a.tv_sec * TIMER_HZ + a.tv_usec; printf("=> %lu (usecs)\n", timer); } unsigned long timer_tol(timeval_t a) { unsigned long timer; timer = a.tv_sec * TIMER_HZ + a.tv_usec; return timer; } keepalived-1.2.7/lib/scheduler.c0000664000175000017500000004111612017240230016332 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Scheduling framework. This code is highly inspired from * the thread management routine (thread.c) present in the * very nice zebra project (http://www.zebra.org). * * 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, */ /* SNMP should be included first: it redefines "FREE" */ #ifdef _WITH_SNMP_ #include #include #include #include #undef FREE #endif #include #include #include #include #include "scheduler.h" #include "memory.h" #include "utils.h" #include "signals.h" #include "logger.h" /* global vars */ thread_master_t *master = NULL; /* Make thread master. */ thread_master_t * thread_make_master(void) { thread_master_t *new; new = (thread_master_t *) MALLOC(sizeof (thread_master_t)); return new; } /* Add a new thread to the list. */ static void thread_list_add(thread_list_t * list, thread_t * thread) { thread->next = NULL; thread->prev = list->tail; if (list->tail) list->tail->next = thread; else list->head = thread; list->tail = thread; list->count++; } /* Add a new thread to the list. */ void thread_list_add_before(thread_list_t * list, thread_t * point, thread_t * thread) { thread->next = point; thread->prev = point->prev; if (point->prev) point->prev->next = thread; else list->head = thread; point->prev = thread; list->count++; } /* Add a thread in the list sorted by timeval */ void thread_list_add_timeval(thread_list_t * list, thread_t * thread) { thread_t *tt; for (tt = list->head; tt; tt = tt->next) { if (timer_cmp(thread->sands, tt->sands) <= 0) break; } if (tt) thread_list_add_before(list, tt, thread); else thread_list_add(list, thread); } /* Delete a thread from the list. */ thread_t * thread_list_delete(thread_list_t * list, thread_t * thread) { if (thread->next) thread->next->prev = thread->prev; else list->tail = thread->prev; if (thread->prev) thread->prev->next = thread->next; else list->head = thread->next; thread->next = thread->prev = NULL; list->count--; return thread; } /* Free all unused thread. */ static void thread_clean_unuse(thread_master_t * m) { thread_t *thread; thread = m->unuse.head; while (thread) { thread_t *t; t = thread; thread = t->next; thread_list_delete(&m->unuse, t); /* free the thread */ FREE(t); m->alloc--; } } /* Move thread to unuse list. */ static void thread_add_unuse(thread_master_t * m, thread_t * thread) { assert(m != NULL); assert(thread->next == NULL); assert(thread->prev == NULL); assert(thread->type == THREAD_UNUSED); thread_list_add(&m->unuse, thread); } /* Move list element to unuse queue */ static void thread_destroy_list(thread_master_t * m, thread_list_t thread_list) { thread_t *thread; thread = thread_list.head; while (thread) { thread_t *t; t = thread; thread = t->next; if (t->type == THREAD_READY_FD || t->type == THREAD_READ || t->type == THREAD_WRITE || t->type == THREAD_READ_TIMEOUT || t->type == THREAD_WRITE_TIMEOUT) close (t->u.fd); thread_list_delete(&thread_list, t); t->type = THREAD_UNUSED; thread_add_unuse(m, t); } } /* Cleanup master */ static void thread_cleanup_master(thread_master_t * m) { /* Unuse current thread lists */ thread_destroy_list(m, m->read); thread_destroy_list(m, m->write); thread_destroy_list(m, m->timer); thread_destroy_list(m, m->event); thread_destroy_list(m, m->ready); /* Clear all FDs */ FD_ZERO(&m->readfd); FD_ZERO(&m->writefd); FD_ZERO(&m->exceptfd); /* Clean garbage */ thread_clean_unuse(m); } /* Stop thread scheduler. */ void thread_destroy_master(thread_master_t * m) { thread_cleanup_master(m); FREE(m); } /* Delete top of the list and return it. */ thread_t * thread_trim_head(thread_list_t * list) { if (list->head) return thread_list_delete(list, list->head); return NULL; } /* Make new thread. */ thread_t * thread_new(thread_master_t * m) { thread_t *new; /* If one thread is already allocated return it */ if (m->unuse.head) { new = thread_trim_head(&m->unuse); memset(new, 0, sizeof (thread_t)); return new; } new = (thread_t *) MALLOC(sizeof (thread_t)); m->alloc++; return new; } /* Add new read thread. */ thread_t * thread_add_read(thread_master_t * m, int (*func) (thread_t *) , void *arg, int fd, long timer) { thread_t *thread; assert(m != NULL); if (FD_ISSET(fd, &m->readfd)) { log_message(LOG_WARNING, "There is already read fd [%d]", fd); return NULL; } thread = thread_new(m); thread->type = THREAD_READ; thread->id = 0; thread->master = m; thread->func = func; thread->arg = arg; FD_SET(fd, &m->readfd); thread->u.fd = fd; /* Compute read timeout value */ set_time_now(); thread->sands = timer_add_long(time_now, timer); /* Sort the thread. */ thread_list_add_timeval(&m->read, thread); return thread; } /* Add new write thread. */ thread_t * thread_add_write(thread_master_t * m, int (*func) (thread_t *) , void *arg, int fd, long timer) { thread_t *thread; assert(m != NULL); if (FD_ISSET(fd, &m->writefd)) { log_message(LOG_WARNING, "There is already write fd [%d]", fd); return NULL; } thread = thread_new(m); thread->type = THREAD_WRITE; thread->id = 0; thread->master = m; thread->func = func; thread->arg = arg; FD_SET(fd, &m->writefd); thread->u.fd = fd; /* Compute write timeout value */ set_time_now(); thread->sands = timer_add_long(time_now, timer); /* Sort the thread. */ thread_list_add_timeval(&m->write, thread); return thread; } /* Add timer event thread. */ thread_t * thread_add_timer(thread_master_t * m, int (*func) (thread_t *) , void *arg, long timer) { thread_t *thread; assert(m != NULL); thread = thread_new(m); thread->type = THREAD_TIMER; thread->id = 0; thread->master = m; thread->func = func; thread->arg = arg; /* Do we need jitter here? */ set_time_now(); thread->sands = timer_add_long(time_now, timer); /* Sort by timeval. */ thread_list_add_timeval(&m->timer, thread); return thread; } /* Add a child thread. */ thread_t * thread_add_child(thread_master_t * m, int (*func) (thread_t *) , void * arg, pid_t pid, long timer) { thread_t *thread; assert(m != NULL); thread = thread_new(m); thread->type = THREAD_CHILD; thread->id = 0; thread->master = m; thread->func = func; thread->arg = arg; thread->u.c.pid = pid; thread->u.c.status = 0; /* Compute write timeout value */ set_time_now(); thread->sands = timer_add_long(time_now, timer); /* Sort by timeval. */ thread_list_add_timeval(&m->child, thread); return thread; } /* Add simple event thread. */ thread_t * thread_add_event(thread_master_t * m, int (*func) (thread_t *) , void *arg, int val) { thread_t *thread; assert(m != NULL); thread = thread_new(m); thread->type = THREAD_EVENT; thread->id = 0; thread->master = m; thread->func = func; thread->arg = arg; thread->u.val = val; thread_list_add(&m->event, thread); return thread; } /* Add simple event thread. */ thread_t * thread_add_terminate_event(thread_master_t * m) { thread_t *thread; assert(m != NULL); thread = thread_new(m); thread->type = THREAD_TERMINATE; thread->id = 0; thread->master = m; thread->func = NULL; thread->arg = NULL; thread->u.val = 0; thread_list_add(&m->event, thread); return thread; } /* Cancel thread from scheduler. */ void thread_cancel(thread_t * thread) { switch (thread->type) { case THREAD_READ: assert(FD_ISSET(thread->u.fd, &thread->master->readfd)); FD_CLR(thread->u.fd, &thread->master->readfd); thread_list_delete(&thread->master->read, thread); break; case THREAD_WRITE: assert(FD_ISSET(thread->u.fd, &thread->master->writefd)); FD_CLR(thread->u.fd, &thread->master->writefd); thread_list_delete(&thread->master->write, thread); break; case THREAD_TIMER: thread_list_delete(&thread->master->timer, thread); break; case THREAD_CHILD: /* Does this need to kill the child, or is that the * caller's job? * This function is currently unused, so leave it for now. */ thread_list_delete(&thread->master->child, thread); break; case THREAD_EVENT: thread_list_delete(&thread->master->event, thread); break; case THREAD_READY: case THREAD_READY_FD: thread_list_delete(&thread->master->ready, thread); break; default: break; } thread->type = THREAD_UNUSED; thread_add_unuse(thread->master, thread); } /* Delete all events which has argument value arg. */ void thread_cancel_event(thread_master_t * m, void *arg) { thread_t *thread; thread = m->event.head; while (thread) { thread_t *t; t = thread; thread = t->next; if (t->arg == arg) { thread_list_delete(&m->event, t); t->type = THREAD_UNUSED; thread_add_unuse(m, t); } } } /* Update timer value */ static void thread_update_timer(thread_list_t *list, timeval_t *timer_min) { if (list->head) { if (!timer_isnull(*timer_min)) { if (timer_cmp(list->head->sands, *timer_min) <= 0) { *timer_min = list->head->sands; } } else { *timer_min = list->head->sands; } } } /* Compute the wait timer. Take care of timeouted fd */ static void thread_compute_timer(thread_master_t * m, timeval_t * timer_wait) { timeval_t timer_min; /* Prepare timer */ timer_reset(timer_min); thread_update_timer(&m->timer, &timer_min); thread_update_timer(&m->write, &timer_min); thread_update_timer(&m->read, &timer_min); thread_update_timer(&m->child, &timer_min); /* Take care about monothonic clock */ if (!timer_isnull(timer_min)) { timer_min = timer_sub(timer_min, time_now); if (timer_min.tv_sec < 0) { timer_min.tv_sec = timer_min.tv_usec = 0; } else if (timer_min.tv_sec >= 1) { timer_min.tv_sec = 1; timer_min.tv_usec = 0; } timer_wait->tv_sec = timer_min.tv_sec; timer_wait->tv_usec = timer_min.tv_usec; } else { timer_wait->tv_sec = 1; timer_wait->tv_usec = 0; } } /* Fetch next ready thread. */ thread_t * thread_fetch(thread_master_t * m, thread_t * fetch) { int ret, old_errno; thread_t *thread; fd_set readfd; fd_set writefd; fd_set exceptfd; timeval_t timer_wait; int signal_fd; #ifdef _WITH_SNMP_ timeval_t snmp_timer_wait; int snmpblock = 0; int fdsetsize; #endif assert(m != NULL); /* Timer initialization */ memset(&timer_wait, 0, sizeof (timeval_t)); retry: /* When thread can't fetch try to find next thread again. */ /* If there is event process it first. */ while ((thread = thread_trim_head(&m->event))) { *fetch = *thread; /* If daemon hanging event is received return NULL pointer */ if (thread->type == THREAD_TERMINATE) { thread->type = THREAD_UNUSED; thread_add_unuse(m, thread); return NULL; } thread->type = THREAD_UNUSED; thread_add_unuse(m, thread); return fetch; } /* If there is ready threads process them */ while ((thread = thread_trim_head(&m->ready))) { *fetch = *thread; thread->type = THREAD_UNUSED; thread_add_unuse(m, thread); return fetch; } /* * Re-read the current time to get the maximum accuracy. * Calculate select wait timer. Take care of timeouted fd. */ set_time_now(); thread_compute_timer(m, &timer_wait); /* Call select function. */ readfd = m->readfd; writefd = m->writefd; exceptfd = m->exceptfd; signal_fd = signal_rfd(); FD_SET(signal_fd, &readfd); #ifdef _WITH_SNMP_ /* When SNMP is enabled, we may have to select() on additional * FD. snmp_select_info() will add them to `readfd'. The trick * with this function is its last argument. We need to set it * to 0 and we need to use the provided new timer only if it * is still set to 0. */ fdsetsize = FD_SETSIZE; snmpblock = 0; memcpy(&snmp_timer_wait, &timer_wait, sizeof(timeval_t)); snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock); if (snmpblock == 0) memcpy(&timer_wait, &snmp_timer_wait, sizeof(timeval_t)); #endif ret = select(FD_SETSIZE, &readfd, &writefd, &exceptfd, &timer_wait); /* we have to save errno here because the next syscalls will set it */ old_errno = errno; /* Handle SNMP stuff */ #ifdef _WITH_SNMP_ if (ret > 0) snmp_read(&readfd); else if (ret == 0) snmp_timeout(); #endif /* handle signals synchronously, including child reaping */ if (FD_ISSET(signal_fd, &readfd)) signal_run_callback(); /* Update current time */ set_time_now(); if (ret < 0) { if (old_errno == EINTR) goto retry; /* Real error. */ DBG("select error: %s", strerror(old_errno)); assert(0); } /* Timeout children */ thread = m->child.head; while (thread) { thread_t *t; t = thread; thread = t->next; if (timer_cmp(time_now, t->sands) >= 0) { thread_list_delete(&m->child, t); thread_list_add(&m->ready, t); t->type = THREAD_CHILD_TIMEOUT; } } /* Read thead. */ thread = m->read.head; while (thread) { thread_t *t; t = thread; thread = t->next; if (FD_ISSET(t->u.fd, &readfd)) { assert(FD_ISSET(t->u.fd, &m->readfd)); FD_CLR(t->u.fd, &m->readfd); thread_list_delete(&m->read, t); thread_list_add(&m->ready, t); t->type = THREAD_READY_FD; } else { if (timer_cmp(time_now, t->sands) >= 0) { FD_CLR(t->u.fd, &m->readfd); thread_list_delete(&m->read, t); thread_list_add(&m->ready, t); t->type = THREAD_READ_TIMEOUT; } } } /* Write thead. */ thread = m->write.head; while (thread) { thread_t *t; t = thread; thread = t->next; if (FD_ISSET(t->u.fd, &writefd)) { assert(FD_ISSET(t->u.fd, &writefd)); FD_CLR(t->u.fd, &m->writefd); thread_list_delete(&m->write, t); thread_list_add(&m->ready, t); t->type = THREAD_READY_FD; } else { if (timer_cmp(time_now, t->sands) >= 0) { FD_CLR(t->u.fd, &m->writefd); thread_list_delete(&m->write, t); thread_list_add(&m->ready, t); t->type = THREAD_WRITE_TIMEOUT; } } } /* Exception thead. */ /*... */ /* Timer update. */ thread = m->timer.head; while (thread) { thread_t *t; t = thread; thread = t->next; if (timer_cmp(time_now, t->sands) >= 0) { thread_list_delete(&m->timer, t); thread_list_add(&m->ready, t); t->type = THREAD_READY; } } /* Return one event. */ thread = thread_trim_head(&m->ready); #ifdef _WITH_SNMP_ run_alarms(); netsnmp_check_outstanding_agent_requests(); #endif /* There is no ready thread. */ if (!thread) goto retry; *fetch = *thread; thread->type = THREAD_UNUSED; thread_add_unuse(m, thread); return fetch; } /* Synchronous signal handler to reap child processes */ void thread_child_handler(void * v, int sig) { thread_master_t * m = v; /* * This is O(n^2), but there will only be a few entries on * this list. */ thread_t *thread; pid_t pid; int status = 77; while ((pid = waitpid(-1, &status, WNOHANG))) { if (pid == -1) { if (errno == ECHILD) return; DBG("waitpid error: %s", strerror(errno)); assert(0); } else { thread = m->child.head; while (thread) { thread_t *t; t = thread; thread = t->next; if (pid == t->u.c.pid) { thread_list_delete(&m->child, t); thread_list_add(&m->ready, t); t->u.c.status = status; t->type = THREAD_READY; break; } } } } } /* Make unique thread id for non pthread version of thread manager. */ unsigned long int thread_get_id(void) { static unsigned long int counter = 0; return ++counter; } /* Call thread ! */ void thread_call(thread_t * thread) { thread->id = thread_get_id(); (*thread->func) (thread); } /* Our infinite scheduling loop */ void launch_scheduler(void) { thread_t thread; signal_set(SIGCHLD, thread_child_handler, master); /* * Processing the master thread queues, * return and execute one ready thread. */ while (thread_fetch(master, &thread)) { /* Run until error, used for debuging only */ #ifdef _DEBUG_ if ((debug & 520) == 520) { debug &= ~520; thread_add_terminate_event(master); } #endif thread_call(&thread); } } keepalived-1.2.7/lib/list.c0000664000175000017500000000725712017240230015337 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: List structure 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, */ #include "list.h" #include "memory.h" /* Simple list helpers functions */ list alloc_list(void (*free_func) (void *), void (*dump_func) (void *)) { return alloc_mlist(free_func, dump_func, 1); } static element alloc_element(void) { element new = (element) MALLOC(sizeof (struct _element)); return new; } void list_add(list l, void *data) { element e = alloc_element(); e->prev = l->tail; e->data = data; if (l->head == NULL) l->head = e; else l->tail->next = e; l->tail = e; l->count++; } void list_del(list l, void *data) { element e; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { if (ELEMENT_DATA(e) == data) { 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); return; } } } void * list_element(list l, int num) { element e = LIST_HEAD(l); int i = 0; /* fetch element number num */ for (i = 0; i < num; i++) if (e) ELEMENT_NEXT(e); if (e) return ELEMENT_DATA(e); return NULL; } void dump_list(list l) { element e; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) if (l->dump) (*l->dump) (e->data); } static void free_element(list l) { element e; element next; for (e = LIST_HEAD(l); e; e = next) { next = e->next; if (l->free) (*l->free) (e->data); l->count--; FREE(e); } } void free_list_elements(list l) { element e; element next; for (e = LIST_HEAD(l); e; e = next) { next = e->next; l->count--; FREE(e); } l->head = NULL; l->tail = NULL; } void free_list(list l) { if (!l) return; free_element(l); FREE(l); } void free_list_element(list l, element e) { if (!e) return; if (l->head == e) l->head = (e->next == e) ? NULL : e->next; if (l->tail == e) l->tail = (e->prev == e) ? NULL : e->prev; if (e->prev) e->prev->next = e->next; if (e->next) e->next->prev = e->prev; if (l->free) (*l->free) (e->data); l->count--; FREE(e); } /* Multiple list helpers functions */ list alloc_mlist(void (*free_func) (void *), void (*dump_func) (void *), int size) { list new = (list) MALLOC(size * sizeof (struct _list)); new->free = free_func; new->dump = dump_func; return new; } void dump_mlist(list l, int size) { element e; int i; for (i = 0; i < size; i++) { for (e = LIST_HEAD(&l[i]); e; ELEMENT_NEXT(e)) if (l->dump) (*l->dump) (e->data); } } void free_melement(list l, void (*free_func) (void *)) { element e; element next; for (e = LIST_HEAD(l); e; e = next) { next = e->next; if (free_func) (*free_func) (e->data); FREE(e); } } void free_mlist(list l, int size) { int i; if (!l) return; for (i = 0; i < size; i++) free_melement(&l[i], l->free); FREE(l); } keepalived-1.2.7/lib/parser.h0000664000175000017500000000470612017240230015661 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: cfreader.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 _PARSER_H #define _PARSER_H /* system includes */ #include #include #include #include #include #include /* local includes */ #include "vector.h" /* Global definitions */ #define CONF "/etc/keepalived/keepalived.conf" #define EOB "}" #define MAXBUF 1024 /* ketword definition */ typedef struct _keyword { char *string; void (*handler) (vector_t *); vector_t *sub; } keyword_t; /* Reloading helpers */ #define SET_RELOAD (reload = 1) #define UNSET_RELOAD (reload = 0) #define RELOAD_DELAY 5 /* global vars exported */ extern vector_t *keywords; extern FILE *current_stream; extern int reload; /* Prototypes */ extern void keyword_alloc(vector_t *, char *, void (*handler) (vector_t *)); extern void keyword_alloc_sub(vector_t *, char *, void (*handler) (vector_t *)); extern void install_keyword_root(char *, void (*handler) (vector_t *)); extern void install_sublevel(void); extern void install_sublevel_end(void); extern void install_keyword(char *, void (*handler) (vector_t *)); extern void dump_keywords(vector_t *, int); extern void free_keywords(vector_t *); extern vector_t *alloc_strvec(char *); extern int read_line(char *, int); extern vector_t *read_value_block(void); extern void alloc_value_block(vector_t *, void (*alloc_func) (vector_t *)); extern void *set_value(vector_t *); extern void process_stream(vector_t *); extern void init_data(char *, vector_t * (*init_keywords) (void)); #endif keepalived-1.2.7/lib/Makefile.in0000664000175000017500000000164312017240230016256 0ustar acassenacassen# Makefile # # Keepalived OpenSource project. # # Copyright (C) 2001-2011 Alexandre Cassen, CC = @CC@ INCLUDES = -I. CFLAGS = @CFLAGS@ $(INCLUDES) \ -Wall -Wunused -Wstrict-prototypes DEFS = @DFLAGS@ -D@SNMP_SUPPORT@ COMPILE = $(CC) $(CFLAGS) $(DEFS) OBJS = memory.o utils.o notify.o timer.o scheduler.o \ vector.o list.o html.o parser.o signals.o logger.o \ list_head.o HEADERS = $(OBJS:.o=.h) .c.o: $(COMPILE) -c $< all: $(OBJS) clean: rm -f *.a *.o *~ distclean: clean rm -f Makefile memory.o: memory.c memory.h utils.h utils.o: utils.c utils.h notify.o: notify.c notify.h timer.o: timer.c timer.h scheduler.o: scheduler.c scheduler.h memory.h utils.h vector.o: vector.c vector.h memory.h list.o: list.c list.h memory.h html.o: html.c html.h memory.h parser.o: parser.c parser.h memory.h signals.o: signals.c signals.h logger.o: logger.c logger.h list_head.o: list_head.c list_head.h keepalived-1.2.7/lib/list.h0000664000175000017500000000422012017240230015327 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: list.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 _LIST_H #define _LIST_H /* list definition */ typedef struct _element *element; typedef struct _list *list; struct _element { struct _element *next; struct _element *prev; void *data; }; struct _list { struct _element *head; struct _element *tail; unsigned int count; void (*free) (void *); void (*dump) (void *); }; /* utility macro */ #define ELEMENT_NEXT(E) ((E) = (E)->next) #define ELEMENT_DATA(E) ((E)->data) #define LIST_HEAD(L) ((L)->head) #define LIST_TAIL_DATA(L) ((L)->tail->data) #define LIST_ISEMPTY(L) ((L) == NULL || ((L)->head == NULL && (L)->tail == NULL)) #define LIST_SIZE(V) ((V)->count) /* Prototypes */ extern list alloc_list(void (*free_func) (void *), void (*dump_func) (void *)); extern void free_list(list l); extern void free_list_elements(list l); extern void free_list_element(list l, element e); extern void *list_element(list l, int num); extern void dump_list(list l); extern void list_add(list l, void *data); extern void list_del(list l, void *data); extern list alloc_mlist(void (*free_func) (void *), void (*dump_func) (void *), int size); extern void dump_mlist(list l, int size); extern void free_mlist(list l, int size); #endif keepalived-1.2.7/lib/utils.c0000664000175000017500000001610712017240230015516 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: General program utils. * * 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 "utils.h" /* global vars */ int debug = 0; /* Display a buffer into a HEXA formated output */ void dump_buffer(char *buff, int count) { int i, j, c; int printnext = 1; if (count % 16) c = count + (16 - count % 16); else c = count; for (i = 0; i < c; i++) { if (printnext) { printnext--; printf("%.4x ", i & 0xffff); } if (i < count) printf("%3.2x", buff[i] & 0xff); else printf(" "); if (!((i + 1) % 8)) { if ((i + 1) % 16) printf(" -"); else { printf(" "); for (j = i - 15; j <= i; j++) if (j < count) { if ((buff[j] & 0xff) >= 0x20 && (buff[j] & 0xff) <= 0x7e) printf("%c", buff[j] & 0xff); else printf("."); } else printf(" "); printf("\n"); printnext = 1; } } } } /* Compute a checksum */ u_short in_csum(u_short * addr, int len, u_short csum) { register int nleft = len; const u_short *w = addr; register u_short answer; register int sum = csum; /* * Our algorithm is simple, using a 32 bit accumulator (sum), * we add sequential 16 bit words to it, and at the end, fold * back all the carry bits from the top 16 bits into the lower * 16 bits. */ while (nleft > 1) { sum += *w++; nleft -= 2; } /* mop up an odd byte, if necessary */ if (nleft == 1) sum += htons(*(u_char *) w << 8); /* * add back carry outs from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return (answer); } /* IP network to ascii representation */ char * inet_ntop2(uint32_t ip) { static char buf[16]; unsigned char *bytep; bytep = (unsigned char *) &(ip); sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]); return buf; } /* * IP network to ascii representation. To use * for multiple IP address convertion into the same call. */ char * inet_ntoa2(uint32_t ip, char *buf) { unsigned char *bytep; bytep = (unsigned char *) &(ip); sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]); return buf; } /* IP string to network mask representation. CIDR notation. */ uint8_t inet_stom(char *addr) { uint8_t mask = 32; char *cp = addr; if (!strstr(addr, "/")) return mask; while (*cp != '/' && *cp != '\0') cp++; if (*cp == '/') return atoi(++cp); return mask; } /* IP string to network range representation. */ uint8_t inet_stor(char *addr) { char *cp = addr; if (!strstr(addr, "-")) return 0; while (*cp != '-' && *cp != '\0') cp++; if (*cp == '-') return strtoul(++cp, NULL, (strchr(addr, ':')) ? 16 : 10); return 0; } /* IP string to sockaddr_storage */ int inet_stosockaddr(char *ip, char *port, struct sockaddr_storage *addr) { void *addr_ip; char *cp = ip; addr->ss_family = (strchr(ip, ':')) ? AF_INET6 : AF_INET; /* remove range and mask stuff */ if (strstr(ip, "-")) { while (*cp != '-' && *cp != '\0') cp++; if (*cp == '-') *cp = 0; } else if (strstr(ip, "/")) { while (*cp != '/' && *cp != '\0') cp++; if (*cp == '/') *cp = 0; } if (addr->ss_family == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr; if (port) addr6->sin6_port = htons(atoi(port)); addr_ip = &addr6->sin6_addr; } else { struct sockaddr_in *addr4 = (struct sockaddr_in *) addr; if (port) addr4->sin_port = htons(atoi(port)); addr_ip = &addr4->sin_addr; } if (!inet_pton(addr->ss_family, ip, addr_ip)) return -1; return 0; } /* IP network to string representation */ char * inet_sockaddrtos2(struct sockaddr_storage *addr, char *addr_str) { void *addr_ip; if (addr->ss_family == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr; addr_ip = &addr6->sin6_addr; } else { struct sockaddr_in *addr4 = (struct sockaddr_in *) addr; addr_ip = &addr4->sin_addr; } if (!inet_ntop(addr->ss_family, addr_ip, addr_str, INET6_ADDRSTRLEN)) return NULL; return addr_str; } char * inet_sockaddrtos(struct sockaddr_storage *addr) { static char addr_str[INET6_ADDRSTRLEN]; inet_sockaddrtos2(addr, addr_str); return addr_str; } uint16_t inet_sockaddrport(struct sockaddr_storage *addr) { uint16_t port; if (addr->ss_family == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr; port = addr6->sin6_port; } else { struct sockaddr_in *addr4 = (struct sockaddr_in *) addr; port = addr4->sin_port; } return port; } uint32_t inet_sockaddrip4(struct sockaddr_storage *addr) { if (addr->ss_family != AF_INET) return -1; return ((struct sockaddr_in *) addr)->sin_addr.s_addr; } int inet_sockaddrip6(struct sockaddr_storage *addr, struct in6_addr *ip6) { if (addr->ss_family != AF_INET6) return -1; *ip6 = ((struct sockaddr_in6 *) addr)->sin6_addr; return 0; } /* * IP string to network representation * Highly inspired from Paul Vixie code. */ int inet_ston(const char *addr, uint32_t * dst) { static char digits[] = "0123456789"; int saw_digit, octets, ch; u_char tmp[INADDRSZ], *tp; saw_digit = 0; octets = 0; *(tp = tmp) = 0; while ((ch = *addr++) != '\0' && ch != '/' && ch != '-') { const char *pch; if ((pch = strchr(digits, ch)) != NULL) { u_int new = *tp * 10 + (pch - digits); if (new > 255) return 0; *tp = new; if (!saw_digit) { if (++octets > 4) return 0; saw_digit = 1; } } else if (ch == '.' && saw_digit) { if (octets == 4) return 0; *++tp = 0; saw_digit = 0; } else return 0; } if (octets < 4) return 0; memcpy(dst, tmp, INADDRSZ); return 1; } /* * Return broadcast address from network and netmask. */ uint32_t inet_broadcast(uint32_t network, uint32_t netmask) { return 0xffffffff - netmask + network; } /* * Convert CIDR netmask notation to long notation. */ uint32_t inet_cidrtomask(uint8_t cidr) { uint32_t mask = 0; int b; for (b = 0; b < cidr; b++) mask |= (1 << (31 - b)); return ntohl(mask); } /* Getting localhost official canonical name */ char * get_local_name(void) { struct hostent *host; struct utsname name; if (uname(&name) < 0) return NULL; if (!(host = gethostbyname(name.nodename))) return NULL; return host->h_name; } keepalived-1.2.7/lib/notify.h0000664000175000017500000000221712017240230015670 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: 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 _NOTIFY_H #define _NOTIFY_H /* system includes */ extern int system_call(char *cmdline); extern void closeall(int fd); extern int notify_exec(char *cmd); #endif keepalived-1.2.7/lib/signals.c0000664000175000017500000001122012017240230016005 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Signals framework. * * Author: Kevin Lindsay, * 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 #include #include #include #include #include "signals.h" #include "utils.h" /* Local Vars */ void (*signal_SIGHUP_handler) (void *, int sig); void *signal_SIGHUP_v; void (*signal_SIGINT_handler) (void *, int sig); void *signal_SIGINT_v; void (*signal_SIGTERM_handler) (void *, int sig); void *signal_SIGTERM_v; void (*signal_SIGCHLD_handler) (void *, int sig); void *signal_SIGCHLD_v; static int signal_pipe[2] = { -1, -1 }; /* Local signal test */ int signal_pending(void) { fd_set readset; int rc; struct timeval timeout = { 0, 0 }; FD_ZERO(&readset); FD_SET(signal_pipe[0], &readset); rc = select(signal_pipe[0] + 1, &readset, NULL, NULL, &timeout); return rc>0?1:0; } /* Signal flag */ void signal_handler(int sig) { if (write(signal_pipe[1], &sig, sizeof(int)) != sizeof(int)) { DBG("signal_pipe write error %s", strerror(errno)); assert(0); } } /* Signal wrapper */ void * signal_set(int signo, void (*func) (void *, int), void *v) { int ret; struct sigaction sig; struct sigaction osig; sig.sa_handler = signal_handler; sigemptyset(&sig.sa_mask); sig.sa_flags = 0; #ifdef SA_RESTART sig.sa_flags |= SA_RESTART; #endif /* SA_RESTART */ ret = sigaction(signo, &sig, &osig); switch(signo) { case SIGHUP: signal_SIGHUP_handler = func; signal_SIGHUP_v = v; break; case SIGINT: signal_SIGINT_handler = func; signal_SIGINT_v = v; break; case SIGTERM: signal_SIGTERM_handler = func; signal_SIGTERM_v = v; break; case SIGCHLD: signal_SIGCHLD_handler = func; signal_SIGCHLD_v = v; break; } if (ret < 0) return (SIG_ERR); else return (osig.sa_handler); } /* Signal Ignore */ void * signal_ignore(int signo) { return signal_set(signo, NULL, NULL); } /* Handlers intialization */ void signal_handler_init(void) { int n = pipe(signal_pipe); assert(!n); fcntl(signal_pipe[0], F_SETFL, O_NONBLOCK | fcntl(signal_pipe[0], F_GETFL)); fcntl(signal_pipe[1], F_SETFL, O_NONBLOCK | fcntl(signal_pipe[1], F_GETFL)); signal_SIGHUP_handler = NULL; signal_SIGINT_handler = NULL; signal_SIGTERM_handler = NULL; signal_SIGCHLD_handler = NULL; } void signal_wait_handlers(void) { struct sigaction sig; sig.sa_handler = SIG_DFL; sigemptyset(&sig.sa_mask); sig.sa_flags = 0; /* Ensure no more pending signals */ sigaction(SIGHUP, &sig, NULL); sigaction(SIGINT, &sig, NULL); sigaction(SIGTERM, &sig, NULL); sigaction(SIGCHLD, &sig, NULL); /* reset */ signal_SIGHUP_v = NULL; signal_SIGINT_v = NULL; signal_SIGTERM_v = NULL; signal_SIGCHLD_v = NULL; } void signal_reset(void) { signal_wait_handlers(); signal_SIGHUP_handler = NULL; signal_SIGINT_handler = NULL; signal_SIGTERM_handler = NULL; signal_SIGCHLD_handler = NULL; } void signal_handler_destroy(void) { signal_wait_handlers(); close(signal_pipe[1]); close(signal_pipe[0]); signal_pipe[1] = -1; signal_pipe[0] = -1; } int signal_rfd(void) { return(signal_pipe[0]); } /* Handlers callback */ void signal_run_callback(void) { int sig; while(read(signal_pipe[0], &sig, sizeof(int)) == sizeof(int)) { switch(sig) { case SIGHUP: if (signal_SIGHUP_handler) signal_SIGHUP_handler(signal_SIGHUP_v, SIGHUP); break; case SIGINT: if (signal_SIGINT_handler) signal_SIGINT_handler(signal_SIGINT_v, SIGINT); break; case SIGTERM: if (signal_SIGTERM_handler) signal_SIGTERM_handler(signal_SIGTERM_v, SIGTERM); break; case SIGCHLD: if (signal_SIGCHLD_handler) signal_SIGCHLD_handler(signal_SIGCHLD_v, SIGCHLD); break; default: break; } } } keepalived-1.2.7/lib/notify.c0000664000175000017500000000425012017240230015662 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Forked system call to launch an extra script. * * 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 #include "notify.h" #include "signals.h" #include "logger.h" /* perform a system call */ int system_call(char *cmdline) { int retval; retval = system(cmdline); if (retval == 127) { /* couldn't exec command */ log_message(LOG_ALERT, "Couldn't exec command: %s", cmdline); } else if (retval == -1) { /* other error */ log_message(LOG_ALERT, "Error exec-ing command: %s", cmdline); } return retval; } /* Close all FDs >= a specified value */ void closeall(int fd) { int fdlimit = sysconf(_SC_OPEN_MAX); while (fd < fdlimit) close(fd++); } /* Execute external script/program */ int notify_exec(char *cmd) { pid_t pid; int ret; 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) return 0; 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"); } system_call(cmd); exit(0); } keepalived-1.2.7/lib/vector.c0000664000175000017500000001243112017240230015654 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Vector structure 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, */ #include "vector.h" #include "memory.h" /* * Initialize vector struct. * allocalted 'size' slot elements then return vector. */ vector_t * vector_alloc(void) { vector_t *v = (vector_t *) MALLOC(sizeof(vector_t)); return v; } vector_t * vector_init(unsigned int size) { vector_t *v = vector_alloc(); /* allocate at least one slot */ if (size == 0) size = 1; v->allocated = size; v->active = 0; v->slot = (void *) MALLOC(sizeof(void *) * size); return v; } /* allocated one slot */ void vector_alloc_slot(vector_t *v) { v->allocated += VECTOR_DEFAULT_SIZE; if (v->slot) v->slot = REALLOC(v->slot, sizeof (void *) * v->allocated); else v->slot = (void *) MALLOC(sizeof (void *) * v->allocated); } /* Insert a value into a specific slot */ void vector_insert_slot(vector_t *v, int index, void *value) { int i; vector_alloc_slot(v); for (i = (v->allocated / VECTOR_DEFAULT_SIZE) - 2; i >= index; i--) v->slot[i + 1] = v->slot[i]; v->slot[index] = value; } /* Copy / dup a vector */ vector_t * vector_copy(vector_t *v) { unsigned int size; vector_t *new = vector_alloc(); new->active = v->active; new->allocated = v->allocated; size = sizeof(void *) * (v->allocated); new->slot = (void *) MALLOC(size); memcpy(new->slot, v->slot, size); return new; } /* Check assigned index, and if it runs short double index pointer */ void vector_ensure(vector_t *v, unsigned int num) { if (v->allocated > num) return; v->slot = REALLOC(v->slot, sizeof(void *) * (v->allocated * 2)); memset(&v->slot[v->allocated], 0, sizeof (void *) * v->allocated); v->allocated *= 2; if (v->allocated <= num) vector_ensure(v, num); } /* This function only returns next empty slot index. It dose not mean * the slot's index memory is assigned, please call vector_ensure() * after calling this function. */ int vector_empty_slot(vector_t *v) { unsigned int i; if (v->active == 0) return 0; for (i = 0; i < v->active; i++) { if (v->slot[i] == 0) { return i; } } return i; } /* Set value to the smallest empty slot. */ int vector_set(vector_t *v, void *val) { unsigned int i; i = vector_empty_slot(v); vector_ensure(v, i); v->slot[i] = val; if (v->active <= i) v->active = i + 1; return i; } /* Set a vector slot value */ void vector_set_slot(vector_t *v, void *value) { unsigned int i = v->allocated - 1; v->slot[i] = value; } /* Set value to specified index slot. */ int vector_set_index(vector_t *v, unsigned int i, void *val) { vector_ensure(v, i); v->slot[i] = val; if (v->active <= i) v->active = i + 1; return i; } /* Look up vector. */ void * vector_lookup(vector_t *v, unsigned int i) { if (i >= v->active) return NULL; return v->slot[i]; } /* Lookup vector, ensure it. */ void * vector_lookup_ensure(vector_t *v, unsigned int i) { vector_ensure(v, i); return v->slot[i]; } /* Unset value at specified index slot. */ void vector_unset(vector_t *v, unsigned int i) { if (i >= v->allocated) return; v->slot[i] = NULL; if (i + 1 == v->active) { v->active--; while (i && v->slot[--i] == NULL && v->active--) ; /* Is this ugly ? */ } } /* Count the number of not emplty slot. */ unsigned int vector_count(vector_t *v) { unsigned int i; unsigned count = 0; for (i = 0; i < v->active; i++) { if (v->slot[i] != NULL) { count++; } } return count; } /* Free memory vector allocation */ void vector_only_wrapper_free(vector_t *v) { FREE(v); } void vector_only_slot_free(void *slot) { FREE(slot); } void vector_only_index_free(void *slot) { vector_only_slot_free(slot); } void vector_free(vector_t *v) { FREE(v->slot); FREE(v); } /* dump vector slots */ void vector_dump(vector_t *v) { int i; printf("Vector Size : %d\n", v->allocated); for (i = 0; i < v->allocated; i++) { if (v->slot[i] != NULL) { printf(" Slot [%d]: %p\n", i, vector_slot(v, i)); } } } /* String vector related */ void free_strvec(vector_t *strvec) { int i; char *str; if (!strvec) return; for (i = 0; i < vector_size(strvec); i++) { if ((str = vector_slot(strvec, i)) != NULL) { FREE(str); } } vector_free(strvec); } void dump_strvec(vector_t *strvec) { int i; char *str; if (!strvec) return; printf("String Vector : "); for (i = 0; i < vector_size(strvec); i++) { str = vector_slot(strvec, i); printf("[%i]=%s ", i, str); } printf("\n"); } keepalived-1.2.7/lib/logger.c0000664000175000017500000000271412017240230015634 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: logging facility. * * 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 /* Boolean flag - send messages to console as well as syslog */ static int log_console = 0; void enable_console_log(void) { log_console = 1; } void log_message(const int facility, const char *format, ...) { va_list args; char buf[256]; va_start(args, format); vsnprintf(buf, sizeof(buf), format, args); va_end(args); if (log_console) { fprintf(stderr, "%s\n", buf); } syslog(facility, "%s", buf); } keepalived-1.2.7/lib/list_head.h0000664000175000017500000004140312017240230016314 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: list_head. This code is comming from Linux Kernel. * * 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 _LIST_HEAD_H #define _LIST_HEAD_H #include #include /* * container_of - cast a member of a structure out to the containing structure * * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. * */ #ifndef container_of # define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #endif /* * These are non-NULL pointers that will result in page faults * under normal circumstances, used to verify that nobody uses * non-initialized list entries. */ #define LIST_POISON1 ((void *) 0x00100100) #define LIST_POISON2 ((void *) 0x00200200) /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ typedef struct list_head { struct list_head *next, *prev; } list_head_t; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } /** * list_head_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ static inline void list_head_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static inline void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty on entry does not return true after this, the entry is * in an undefined state. */ static inline void list_head_del(struct list_head *entry) { __list_del(entry->prev, entry->next); entry->next = LIST_POISON1; entry->prev = LIST_POISON2; } /** * list_del_init - deletes entry from list and reinitialize it. * @entry: the element to delete from the list. */ static inline void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } /** * list_move - delete from one list and add as another's head * @list: the entry to move * @head: the head that will precede our entry */ static inline void list_move(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_head_add(list, head); } /** * list_move_tail - delete from one list and add as another's tail * @list: the entry to move * @head: the head that will follow our entry */ static inline void list_move_tail(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add_tail(list, head); } /** * list_is_first - tests whether @list is the first entry in list @head * @list: the entry to test * @head: the head of the list */ static inline int list_is_first(const struct list_head *list, const struct list_head *head) { return list->prev == head; } /** * list_is_last - tests whether @list is the last entry in list @head * @list: the entry to test * @head: the head of the list */ static inline int list_is_last(const struct list_head *list, const struct list_head *head) { return list->next == head; } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static inline int list_empty(const struct list_head *head) { return head->next == head; } static inline void __list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } /** * list_splice - join two lists * @list: the new list to add. * @head: the place to add it in the first list. */ static inline void list_splice(struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head); } /** * list_splice_init - join two lists and reinitialise the emptied list. * @list: the new list to add. * @head: the place to add it in the first list. * * The list at @list is reinitialised */ static inline void list_splice_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head); INIT_LIST_HEAD(list); } } /** * list_sort - merge sort elements of a list. * @head: the head of the list. * @cmp: the function used to compare to list nodes. */ void list_sort(struct list_head *head, int (*cmp)(struct list_head *a, struct list_head *b)); /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ container_of(ptr, type, member) /** * list_first_entry - get the first element from a list * @ptr: the list head to take the element from. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. * * Note, that list is expected to be not empty. */ #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member) /** * list_last_entry - get the last element from a list * @ptr: the list head to take the element from. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. * * Note, that list is expected to be not empty. */ #define list_last_entry(ptr, type, member) \ list_entry((ptr)->prev, type, member) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); \ pos = pos->next) /** * __list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. * * This variant differs from list_for_each() in that it's the * simplest possible list iteration code, no prefetching is done. * Use this for code that knows the list to be very short (empty * or 1 entry) most of the time. */ #define __list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) /** * list_for_each_prev - iterate over a list backwards * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); \ pos = pos->prev) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop counter. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop counter. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_reverse - iterate backwards over list of given type. * @pos: the type * to use as a loop counter. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_reverse(pos, head, member) \ for (pos = list_entry((head)->prev, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.prev, typeof(*pos), member)) /** * list_for_each_entry_continue - iterate over list of given type * continuing after existing point * @pos: the type * to use as a loop counter. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_continue(pos, head, member) \ for (pos = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_continue_reverse - iterate backwards from the given point * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Start to iterate over list of given type backwards, continuing after * the current position. */ #define list_for_each_entry_continue_reverse(pos, head, member) \ for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.prev, typeof(*pos), member)) /** * list_for_each_entry_from - iterate over list of given type from the current point * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type, continuing from current position. */ #define list_for_each_entry_from(pos, head, member) \ for (; &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_from - iterate over list of given type from the current point * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type, continuing from current position. */ #define list_for_each_entry_from_reverse(pos, head, member) \ for (; &pos->member != (head); \ pos = list_entry(pos->member.prev, typeof(*pos), member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @pos: the type * to use as a loop counter. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) /* * Double linked lists with a single pointer list head. * Mostly useful for hash tables where the two pointer list head is * too wasteful. * You lose the ability to access the tail in O(1). */ struct hlist_head { struct hlist_node *first; }; struct hlist_node { struct hlist_node *next, **pprev; }; #define HLIST_HEAD_INIT { .first = NULL } #define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) #define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) static __inline__ int hlist_unhashed(const struct hlist_node *h) { return !h->pprev; } static __inline__ int hlist_empty(const struct hlist_head *h) { return !h->first; } static __inline__ void __hlist_del(struct hlist_node *n) { struct hlist_node *next = n->next; struct hlist_node **pprev = n->pprev; *pprev = next; if (next) next->pprev = pprev; } static __inline__ void hlist_del(struct hlist_node *n) { __hlist_del(n); n->next = LIST_POISON1; n->pprev = LIST_POISON2; } static __inline__ void hlist_del_init(struct hlist_node *n) { if (n->pprev) { __hlist_del(n); INIT_HLIST_NODE(n); } } static __inline__ void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { struct hlist_node *first = h->first; n->next = first; if (first) first->pprev = &n->next; h->first = n; n->pprev = &h->first; } static __inline__ void hlist_add_before(struct hlist_node *n, struct hlist_node *next) { n->pprev = next->pprev; n->next = next; next->pprev = &n->next; *(n->pprev) = n; } static __inline__ void hlist_add_after(struct hlist_node *n, struct hlist_node *next) { next->next = n->next; n->next = next; next->pprev = &n->next; if (next->next) next->next->pprev = &next->next; } #define hlist_entry(ptr, type, member) container_of(ptr,type,member) #define hlist_for_each(pos, head) \ for (pos = (head)->first; pos; pos = pos->next) #define hlist_for_each_safe(pos, n, head) \ for (pos = (head)->first; n = pos ? pos->next : 0, pos; \ pos = n) /** * hlist_for_each_entry - iterate over list of given type * @tpos: the type * to use as a loop counter. * @pos: the &struct hlist_node to use as a loop counter. * @head: the head for your list. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry(tpos, pos, head, member) \ for (pos = (head)->first; \ pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next) /** * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point * @tpos: the type * to use as a loop counter. * @pos: the &struct hlist_node to use as a loop counter. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_continue(tpos, pos, member) \ for (pos = (pos)->next; \ pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next) /** * hlist_for_each_entry_from - iterate over a hlist continuing from existing point * @tpos: the type * to use as a loop counter. * @pos: the &struct hlist_node to use as a loop counter. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_from(tpos, pos, member) \ for (; pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next) /** * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @tpos: the type * to use as a loop counter. * @pos: the &struct hlist_node to use as a loop counter. * @n: another &struct hlist_node to use as temporary storage * @head: the head for your list. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ for (pos = (head)->first; \ pos && ({ n = pos->next; 1; }) && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = n) #define hlist_insert_sorted(tpos, ntpos, pos, head, smember, hmember, res) \ res = 0; \ tpos = NULL; \ hlist_for_each_entry(tpos, pos, (head), hmember) \ if (ntpos->smember <= tpos->smember) \ break; \ if (tpos) { \ if (ntpos->smember < tpos->smember) \ hlist_add_before(&ntpos->hmember, &tpos->hmember); \ else if (ntpos->smember > tpos->smember) \ hlist_add_after(&tpos->hmember, &ntpos->hmember); \ else \ res = 1; \ } else \ hlist_add_head(&ntpos->hmember, (head)); #endif /* ! _LIST_HEAD_H */ keepalived-1.2.7/lib/timer.h0000664000175000017500000000354312017240230015503 0ustar acassenacassen/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: timer.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 _TIMER_H #define _TIMER_H #include typedef struct timeval timeval_t; /* Global vars */ extern timeval_t time_now; /* Some defines */ #define TIME_MAX_FORWARD_US 2000000 #define TIMER_HZ 1000000 #define TIMER_MAX_SEC 1000 /* Some usefull macros */ #define timer_sec(T) ((T).tv_sec) #define timer_long(T) ((T).tv_sec * TIMER_HZ + (T).tv_usec) #define timer_isnull(T) ((T).tv_sec == 0 && (T).tv_usec == 0) #define timer_reset(T) (memset(&(T), 0, sizeof(timeval_t))) /* prototypes */ extern timeval_t timer_now(void); extern timeval_t set_time_now(void); extern timeval_t timer_dup(timeval_t); extern int timer_cmp(timeval_t, timeval_t); extern timeval_t timer_sub(timeval_t, timeval_t); extern timeval_t timer_add_long(timeval_t, long); extern timeval_t timer_sub_now(timeval_t); extern void timer_dump(timeval_t); extern unsigned long timer_tol(timeval_t); #endif keepalived-1.2.7/install-sh0000775000175000017500000001273612001611314015452 0ustar acassenacassen#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 keepalived-1.2.7/VERSION0000664000175000017500000000000612017251663014517 0ustar acassenacassen1.2.7 keepalived-1.2.7/genhash/0000775000175000017500000000000012017252420015060 5ustar acassenacassenkeepalived-1.2.7/genhash/main.c0000664000175000017500000001334512012246161016156 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" /* 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) { 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 --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); } /* Command line parser */ static int parse_cmdline(int argc, char **argv, REQ * req_obj) { poptContext context; char *optarg = NULL; int c; struct poptOption options_table[] = { {"release", 'r', POPT_ARG_NONE, NULL, 'r'}, {"help", 'h', POPT_ARG_NONE, NULL, 'h'}, {"verbose", 'v', POPT_ARG_NONE, NULL, 'v'}, {"use-ssl", 'S', POPT_ARG_NONE, NULL, 'S'}, {"server", 's', POPT_ARG_STRING, &optarg, 's'}, {"port", 'p', POPT_ARG_STRING, &optarg, 'p'}, {"url", 'u', POPT_ARG_STRING, &optarg, 'u'}, {"use-virtualhost", 'V', POPT_ARG_STRING, &optarg, 'V'}, {NULL, 0, 0, NULL, 0} }; /* Parse the command line arguments */ context = poptGetContext(PROG, argc, (const char **) argv, options_table, 0); if ((c = poptGetNextOpt(context)) < 0) { usage(argv[0]); return CMD_LINE_ERROR; } /* The first option car */ 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 (!inet_ston(optarg, &req_obj->addr_ip)) { fprintf(stderr, "server should be an IP, not %s\n", optarg); return CMD_LINE_ERROR; } break; case 'V': req_obj->vhost = optarg; break; default: usage(argv[0]); return CMD_LINE_ERROR; } /* the others */ while ((c = poptGetNextOpt(context)) >= 0) { switch (c) { case 'v': req_obj->verbose = 1; break; case 'S': req_obj->ssl = 1; break; case 's': if (!inet_ston(optarg, &req_obj->addr_ip)) { fprintf(stderr, "server should be an IP, not %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 ((optarg = (char *) poptGetArg(context))) { fprintf(stderr, "unexpected argument %s\n", optarg); return CMD_LINE_ERROR; } /* free the allocated context */ poptFreeContext(context); return CMD_LINE_SUCCESS; } int main(int argc, char **argv) { thread_t thread; /* Allocate the room */ req = (REQ *) MALLOC(sizeof (REQ)); /* Command line parser */ if (!parse_cmdline(argc, argv, req)) { FREE(req); exit(0); } /* Check minimum configuration need */ if (!req->addr_ip && !req->addr_port && !req->url) { FREE(req); exit(0); } /* 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 */ SSL_CTX_free(req->ctx); free_sock(sock); FREE(req); exit(0); } keepalived-1.2.7/genhash/http.c0000664000175000017500000001633212012246161016210 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 */ /* 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[16]; int i; /* Compute final MD5 digest */ MD5_Final(digest, &sock_obj->context); if (req->verbose) { printf("\n"); printf(HTML_MD5); dump_buffer((char *) digest, 16); printf(HTML_MD5_FINAL); } printf("MD5SUM = "); for (i = 0; i < 16; 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->extracted - sock_obj->buffer); 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); MD5_Update(&sock_obj->context, sock_obj->buffer, r); r = 0; } sock_obj->size = r; } else { if (req->verbose) http_dump_header(sock_obj->buffer, sock_obj->size); /* 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); MD5_Update(&sock_obj->context, 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 */ memset(sock_obj->buffer, 0, MAX_BUFFER_LENGTH); r = read(thread->u.fd, sock_obj->buffer + sock_obj->size, MAX_BUFFER_LENGTH - sock_obj->size); 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", inet_ntop2(req->addr_ip), 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 MD5 context */ MD5_Init(&sock_obj->context); /* 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; 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); snprintf(str_request, GET_BUFFER_LENGTH, REQUEST_TEMPLATE, req->url, (req->vhost) ? req->vhost : inet_ntop2(req->addr_ip) , ntohs(req->addr_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", inet_ntop2(req->addr_ip) , 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.7/genhash/ssl.c0000664000175000017500000001145112012246161016027 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 */ memset(sock_obj->buffer, 0, MAX_BUFFER_LENGTH); r = SSL_read(sock_obj->ssl, sock_obj->buffer, MAX_BUFFER_LENGTH); 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.7/genhash/sock.c0000664000175000017500000000327012012246161016165 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.7/genhash/sock.h0000664000175000017500000000266012012246161016174 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 #include /* Engine socket pool element structure */ typedef struct { int fd; SSL *ssl; BIO *bio; MD5_CTX 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.7/genhash/COPYING0000664000175000017500000004307612001611314016117 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.7/genhash/AUTHOR0000664000175000017500000000004712001611314016000 0ustar acassenacassenAlexandre Cassen, keepalived-1.2.7/genhash/layer4.c0000664000175000017500000001320112017240230016415 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, uint32_t addr_ip, uint16_t addr_port) { struct linger li = { 0 }; int long_inet; struct sockaddr_in adr_serv; 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)); long_inet = sizeof (struct sockaddr_in); memset(&adr_serv, 0, long_inet); adr_serv.sin_family = AF_INET; adr_serv.sin_port = addr_port; adr_serv.sin_addr.s_addr = addr_ip; /* Make socket non-block. */ val = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, val | O_NONBLOCK); /* 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, uint32_t addr_ip, 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", inet_ntop2(addr_ip), 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", inet_ntop2(addr_ip), 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", inet_ntop2(addr_ip), 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->addr_ip, req->addr_port, tcp_check_thread); switch (sock_obj->status) { case connect_error: DBG("Error connecting server [%s]:%d.\n", inet_ntop2(req->addr_ip), ntohs(req->addr_port)); thread_add_terminate_event(thread->master); return -1; break; case connect_timeout: DBG("Timeout connecting server [%s]:%d.\n", inet_ntop2(req->addr_ip), 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", inet_ntop2(req->addr_ip), 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 ((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->addr_ip, req->addr_port); /* 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.7/genhash/layer4.h0000664000175000017500000000333112012246161016431 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" enum connect_result { connect_error, connect_in_progress, connect_timeout, connect_success }; /* Prototypes defs */ extern enum connect_result tcp_connect(int fd, uint32_t, uint16_t); extern enum connect_result tcp_socket_state(int, thread_t *, uint32_t, 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.7/genhash/Makefile.in0000664000175000017500000000324412012246161017130 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.7/genhash/INSTALL0000664000175000017500000001166612001611314016115 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.7/genhash/VERSION0000664000175000017500000000000612001611314016116 0ustar acassenacassen1.0.0 keepalived-1.2.7/genhash/ssl.h0000664000175000017500000000237612012246161016042 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.7/genhash/README0000664000175000017500000000102512001611314015730 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.7/genhash/ChangeLog0000664000175000017500000000117712001611314016632 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.7/genhash/http.h0000664000175000017500000000420412012246161016210 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:%d\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_MD5 DELIM_BEGIN" HTML MD5 resulting "DELIM_END #define HTML_MD5_FINAL DELIM_BEGIN" HTML MD5 final resulting "DELIM_END /* 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.7/genhash/main.h0000664000175000017500000000426612012246161016165 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 /* local includes */ #include "memory.h" #include "timer.h" #include "http.h" #include "ssl.h" #include "list.h" /* Build version */ #define PROG "genhash" #define VERSION_CODE 0x010000 #define DATE_CODE 0x120b02 #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 { uint32_t addr_ip; uint16_t addr_port; char *url; char *vhost; int verbose; int ssl; SSL_CTX *ctx; SSL_METHOD *meth; 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.7/bin/0000775000175000017500000000000012017251645014223 5ustar acassenacassenkeepalived-1.2.7/bin/.gitignore0000664000175000017500000000000012001611314016163 0ustar acassenacassenkeepalived-1.2.7/README0000664000175000017500000000175712001611314014327 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.7/doc/0000775000175000017500000000000012017240230014204 5ustar acassenacassenkeepalived-1.2.7/doc/KEEPALIVED-MIB0000664000175000017500000016012712017240230016154 0ustar acassenacassen-- ---------------------------------------------------------------------- -- MIB file for keepalived (http://www.keepalived.org) -- ---------------------------------------------------------------------- -- -- There are two sections in this MIB: vrrp and check. KEEPALIVED-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE, MODULE-IDENTITY, Integer32, Unsigned32, Counter32, Counter64, Gauge32, enterprises, NOTIFICATION-TYPE FROM SNMPv2-SMI OBJECT-GROUP, MODULE-COMPLIANCE, NOTIFICATION-GROUP FROM SNMPv2-CONF InetAddressType, InetAddress, InetPortNumber, InetAddressPrefixLength, InetScopeType FROM INET-ADDRESS-MIB InterfaceIndex, ifIndex FROM IF-MIB DisplayString, TEXTUAL-CONVENTION, TruthValue FROM SNMPv2-TC; keepalived MODULE-IDENTITY LAST-UPDATED "201208240000Z" ORGANIZATION "Keepalived" CONTACT-INFO "http://www.keepalived.org" DESCRIPTION "This MIB describes objects used by keepalived, both for VRRP and health checker." REVISION "201208240000Z" DESCRIPTION "routerId added to traps variables" REVISION "200904080000Z" DESCRIPTION "Initial revision" ::= { project 5 } -- We are hosted under Debian OID. See http://dsa.debian.org/iana/ debian OBJECT IDENTIFIER ::= { enterprises 9586 } project OBJECT IDENTIFIER ::= { debian 100 } VrrpState ::= TEXTUAL-CONVENTION STATUS current DESCRIPTION "Represents a VRRP state." SYNTAX INTEGER { init(0), backup(1), master(2), fault(3), unknown(4) } global OBJECT IDENTIFIER ::= { keepalived 1 } vrrp OBJECT IDENTIFIER ::= { keepalived 2 } check OBJECT IDENTIFIER ::= { keepalived 3 } conformance OBJECT IDENTIFIER ::= { keepalived 4 } -- ---------------------------------------------------------------------- -- Global part -- ---------------------------------------------------------------------- version OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Version of keepalived" ::= { global 1 } routerId OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Router ID" ::= { global 2 } mail OBJECT IDENTIFIER ::= { global 3 } smtpServerAddressType OBJECT-TYPE SYNTAX InetAddressType MAX-ACCESS read-only STATUS current DESCRIPTION "Address type for SMTP server." ::= { mail 1 } smtpServerAddress OBJECT-TYPE SYNTAX InetAddress MAX-ACCESS read-only STATUS current DESCRIPTION "Address of SMTP server." ::= { mail 2 } smtpServerTimeout OBJECT-TYPE SYNTAX Unsigned32 UNITS "seconds" MAX-ACCESS read-only STATUS current DESCRIPTION "SMTP server connection timeout." ::= { mail 3 } emailFrom OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Email address for the From field." ::= { mail 4 } emailTable OBJECT-TYPE SYNTAX SEQUENCE OF EmailEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Table of email notification addresses." ::= { mail 5 } emailEntry OBJECT-TYPE SYNTAX EmailEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Email address to be notified with an alert." INDEX { emailIndex } ::= { emailTable 1 } EmailEntry ::= SEQUENCE { emailIndex Integer32, emailAddress DisplayString } emailIndex OBJECT-TYPE SYNTAX Integer32 (1..2147483647) MAX-ACCESS not-accessible STATUS current DESCRIPTION "Index for the email address." ::= { emailEntry 1 } emailAddress OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Email address to be notified when an alert is raised." ::= { emailEntry 2 } trapEnable OBJECT-TYPE SYNTAX INTEGER { enabled(1), disabled(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Indicate whether traps should be sent for various events." ::= { global 4 } linkBeat OBJECT-TYPE SYNTAX INTEGER { netlink(1), polling(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Indicate which method is used to check if a link is up or down. netlink(1) means that the kernel will push a link state change while polling(2) means that the status of the link is checked periodically." ::= { global 5 } -- ---------------------------------------------------------------------- -- VRRP part -- ---------------------------------------------------------------------- -- Sync groups -- see vrrp.h vrrpSyncGroupTable OBJECT-TYPE SYNTAX SEQUENCE OF VrrpSyncGroupEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Table of sync groups" ::= { vrrp 1 } vrrpSyncGroupEntry OBJECT-TYPE SYNTAX VrrpSyncGroupEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information describing a sync group" INDEX { vrrpSyncGroupIndex } ::= { vrrpSyncGroupTable 1 } VrrpSyncGroupEntry ::= SEQUENCE { vrrpSyncGroupIndex Integer32, vrrpSyncGroupName DisplayString, vrrpSyncGroupState VrrpState, vrrpSyncGroupSmtpAlert INTEGER, vrrpSyncGroupNotifyExec INTEGER, vrrpSyncGroupScriptMaster DisplayString, vrrpSyncGroupScriptBackup DisplayString, vrrpSyncGroupScriptFault DisplayString, vrrpSyncGroupScript DisplayString } vrrpSyncGroupIndex OBJECT-TYPE SYNTAX Integer32 (1..2147483647) MAX-ACCESS not-accessible STATUS current DESCRIPTION "Index of the synchronisation group." ::= { vrrpSyncGroupEntry 1 } vrrpSyncGroupName OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Name of the synchronisation group." ::= {vrrpSyncGroupEntry 2 } vrrpSyncGroupState OBJECT-TYPE SYNTAX VrrpState MAX-ACCESS read-only STATUS current DESCRIPTION "Current state of the synchronisation group." ::= {vrrpSyncGroupEntry 3 } vrrpSyncGroupSmtpAlert OBJECT-TYPE SYNTAX INTEGER { enabled(1), disabled(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Will SMTP alert be sent for this synchronisation group?" ::= {vrrpSyncGroupEntry 4 } vrrpSyncGroupNotifyExec OBJECT-TYPE SYNTAX INTEGER { enabled(1), disabled(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Will we execute notification script for this group?" ::= {vrrpSyncGroupEntry 5 } vrrpSyncGroupScriptMaster OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Script to execute when the group becomes master." ::= {vrrpSyncGroupEntry 6 } vrrpSyncGroupScriptBackup OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Script to execute when the group becomes backup." ::= {vrrpSyncGroupEntry 7 } vrrpSyncGroupScriptFault OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Script to execute when the group is in fault state." ::= {vrrpSyncGroupEntry 8 } vrrpSyncGroupScript OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Script to execute whenever a state change occurs." ::= {vrrpSyncGroupEntry 9 } vrrpSyncGroupMemberTable OBJECT-TYPE SYNTAX SEQUENCE OF VrrpSyncGroupMemberEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Table of instances contained in sync groups" ::= { vrrp 2 } vrrpSyncGroupMemberEntry OBJECT-TYPE SYNTAX VrrpSyncGroupMemberEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information describing a member of a sync group" INDEX { vrrpSyncGroupIndex, vrrpSyncGroupMemberInstanceIndex } ::= { vrrpSyncGroupMemberTable 1 } VrrpSyncGroupMemberEntry ::= SEQUENCE { vrrpSyncGroupMemberInstanceIndex Integer32, vrrpSyncGroupMemberName DisplayString } vrrpSyncGroupMemberInstanceIndex OBJECT-TYPE SYNTAX Integer32 (1..2147483647) MAX-ACCESS not-accessible STATUS current DESCRIPTION "Index of an instance in a synchronisation group. There is no relation with this index and the index of the corresponding instance in vrrpInstanceTable. Use the name to find out the corresponding instance." ::= { vrrpSyncGroupMemberEntry 1 } vrrpSyncGroupMemberName OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Name of the instance contained in the synchronisation group." ::= { vrrpSyncGroupMemberEntry 2 } -- VRRP instances -- see vrrp.h vrrpInstanceTable OBJECT-TYPE SYNTAX SEQUENCE OF VrrpInstanceEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Table of VRRP instances" ::= { vrrp 3 } vrrpInstanceEntry OBJECT-TYPE SYNTAX VrrpInstanceEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information describing a sync group" INDEX { vrrpInstanceIndex } ::= { vrrpInstanceTable 1 } VrrpInstanceEntry ::= SEQUENCE { vrrpInstanceIndex INTEGER, vrrpInstanceName DisplayString, vrrpInstanceVirtualRouterId Unsigned32, vrrpInstanceState VrrpState, vrrpInstanceInitialState VrrpState, vrrpInstanceWantedState VrrpState, vrrpInstanceBasePriority Integer32, vrrpInstanceEffectivePriority Integer32, vrrpInstanceVipsStatus INTEGER, vrrpInstancePrimaryInterface DisplayString, vrrpInstanceTrackPrimaryIf INTEGER, vrrpInstanceAdvertisementsInt Unsigned32, vrrpInstancePreempt INTEGER, vrrpInstancePreemptDelay Unsigned32, vrrpInstanceAuthType INTEGER, vrrpInstanceLvsSyncDaemon INTEGER, vrrpInstanceLvsSyncInterface DisplayString, vrrpInstanceSyncGroup DisplayString, vrrpInstanceGarpDelay Unsigned32, vrrpInstanceSmtpAlert INTEGER, vrrpInstanceNotifyExec INTEGER, vrrpInstanceScriptMaster DisplayString, vrrpInstanceScriptBackup DisplayString, vrrpInstanceScriptFault DisplayString, vrrpInstanceScriptStop DisplayString, vrrpInstanceScript DisplayString } vrrpInstanceIndex OBJECT-TYPE SYNTAX INTEGER { static(0) } MAX-ACCESS not-accessible STATUS current DESCRIPTION "Index of the VRRP instance. Instance 0 is for static IP and static routes." ::= { vrrpInstanceEntry 1 } vrrpInstanceName OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Name of the VRRP instance." ::= { vrrpInstanceEntry 2 } vrrpInstanceVirtualRouterId OBJECT-TYPE SYNTAX Unsigned32 MAX-ACCESS read-only STATUS current DESCRIPTION "Virtual Router ID (VRID) for this VRRP instance." ::= { vrrpInstanceEntry 3 } vrrpInstanceState OBJECT-TYPE SYNTAX VrrpState MAX-ACCESS read-only STATUS current DESCRIPTION "Current state of this VRRP instance." ::= { vrrpInstanceEntry 4 } vrrpInstanceInitialState OBJECT-TYPE SYNTAX VrrpState MAX-ACCESS read-only STATUS current DESCRIPTION "Initial state of this VRRP instance." ::= { vrrpInstanceEntry 5 } vrrpInstanceWantedState OBJECT-TYPE SYNTAX VrrpState MAX-ACCESS read-only STATUS current DESCRIPTION "State wanted by the operator for this VRRP instance." ::= { vrrpInstanceEntry 6 } vrrpInstanceBasePriority OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-write STATUS current DESCRIPTION "Base priority (as defined in the configuration file) for this VRRP instance. This value can be modified to force the virtual router instance to become backup or master. " ::= { vrrpInstanceEntry 7 } vrrpInstanceEffectivePriority OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "Effective priority for this VRRP instance. Status of interfaces and script results are used to compute this value from the base priority." ::= { vrrpInstanceEntry 8 } vrrpInstanceVipsStatus OBJECT-TYPE SYNTAX INTEGER { allSet(1), notAllSet(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Are all VIP of this VRRP instance enabled?" ::= { vrrpInstanceEntry 9 } vrrpInstancePrimaryInterface OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Primary interface of this VRRP instance." ::= { vrrpInstanceEntry 10 } vrrpInstanceTrackPrimaryIf OBJECT-TYPE SYNTAX INTEGER { tracked(1), notTracked(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Do we track the status of the primary interface?" ::= { vrrpInstanceEntry 11 } vrrpInstanceAdvertisementsInt OBJECT-TYPE SYNTAX Unsigned32 UNITS "seconds" MAX-ACCESS read-only STATUS current DESCRIPTION "Delay in seconds between two VRRP advertisements." ::= { vrrpInstanceEntry 12 } vrrpInstancePreempt OBJECT-TYPE SYNTAX INTEGER { preempt(1), noPreempt(2) } MAX-ACCESS read-write STATUS current DESCRIPTION "Will a higher priority advertisement preempt a lower instance?" ::= { vrrpInstanceEntry 13 } vrrpInstancePreemptDelay OBJECT-TYPE SYNTAX Unsigned32 UNITS "seconds" MAX-ACCESS read-only STATUS current DESCRIPTION "Delay after startup until preemption can happen. 0 means that there is no delay." ::= { vrrpInstanceEntry 14 } vrrpInstanceAuthType OBJECT-TYPE SYNTAX INTEGER { none(0), password(1), ah(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Authentication method to authenticate other peers." ::= { vrrpInstanceEntry 15 } vrrpInstanceLvsSyncDaemon OBJECT-TYPE SYNTAX INTEGER { enabled(1), disabled(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Is LVS sync daemon enabled for this VRRP instance?" ::= { vrrpInstanceEntry 16 } vrrpInstanceLvsSyncInterface OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "If LVS sync daemon is enabled, which interface to use for syncing?" ::= { vrrpInstanceEntry 17 } vrrpInstanceSyncGroup OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Name of the synchronisation group this VRRP instance belongs, if any." ::= { vrrpInstanceEntry 18 } vrrpInstanceGarpDelay OBJECT-TYPE SYNTAX Unsigned32 UNITS "seconds" MAX-ACCESS read-only STATUS current DESCRIPTION "Delay to launch gratuitous ARP (GARP)." ::= { vrrpInstanceEntry 19 } vrrpInstanceSmtpAlert OBJECT-TYPE SYNTAX INTEGER { enabled(1), disabled(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Will SMTP alert be sent for this VRRP instance?" ::= { vrrpInstanceEntry 20 } vrrpInstanceNotifyExec OBJECT-TYPE SYNTAX INTEGER { enabled(1), disabled(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Will we execute notification script for this instance?" ::= { vrrpInstanceEntry 21 } vrrpInstanceScriptMaster OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Script to execute when the instance becomes master." ::= { vrrpInstanceEntry 22 } vrrpInstanceScriptBackup OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Script to execute when the instance becomes backup." ::= { vrrpInstanceEntry 23 } vrrpInstanceScriptFault OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Script to execute when the instance is in fault state." ::= { vrrpInstanceEntry 24 } vrrpInstanceScriptStop OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Script to execute when the instance is stopped." ::= { vrrpInstanceEntry 25 } vrrpInstanceScript OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Script to execute whenever a state change occurs." ::= { vrrpInstanceEntry 26 } vrrpTrackedInterfaceTable OBJECT-TYPE SYNTAX SEQUENCE OF VrrpTrackedInterfaceEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Table of tracked interfaces for each VRRP instance." ::= { vrrp 4 } vrrpTrackedInterfaceEntry OBJECT-TYPE SYNTAX VrrpTrackedInterfaceEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information describing a tracked interface" INDEX { vrrpInstanceIndex, ifIndex } ::= { vrrpTrackedInterfaceTable 1 } VrrpTrackedInterfaceEntry ::= SEQUENCE { vrrpTrackedInterfaceName DisplayString, vrrpTrackedInterfaceWeight Integer32 } vrrpTrackedInterfaceName OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Name of the tracked interface." ::= { vrrpTrackedInterfaceEntry 1 } vrrpTrackedInterfaceWeight OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "Weight of the tracked interface." ::= { vrrpTrackedInterfaceEntry 2 } vrrpTrackedScriptTable OBJECT-TYPE SYNTAX SEQUENCE OF VrrpTrackedScriptEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Table of tracked interfaces for each VRRP instance." ::= { vrrp 5 } vrrpTrackedScriptEntry OBJECT-TYPE SYNTAX VrrpTrackedScriptEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information describing a tracked script" INDEX { vrrpInstanceIndex, vrrpTrackedScriptIndex } ::= { vrrpTrackedScriptTable 1 } VrrpTrackedScriptEntry ::= SEQUENCE { vrrpTrackedScriptIndex Integer32, vrrpTrackedScriptName DisplayString, vrrpTrackedScriptWeight Integer32 } vrrpTrackedScriptIndex OBJECT-TYPE SYNTAX Integer32 (1..2147483647) MAX-ACCESS not-accessible STATUS current DESCRIPTION "Index of the tracked script in the set of tracked scripts for the given VRRP instance. This index has no relation with the index of vrrpScriptTable." ::= { vrrpTrackedScriptEntry 1 } vrrpTrackedScriptName OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Name of the tracked interface." ::= { vrrpTrackedScriptEntry 2 } vrrpTrackedScriptWeight OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "Weight of the tracked interface." ::= { vrrpTrackedScriptEntry 3 } -- IP addresses -- see vrrp_ipaddress.h vrrpAddressTable OBJECT-TYPE SYNTAX SEQUENCE OF VrrpAddressEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Table of static and virtual addresses" ::= { vrrp 6 } vrrpAddressEntry OBJECT-TYPE SYNTAX VrrpAddressEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information describing an address. This can be a static address or a virtual address. In case of static address, the VRRP instance index is 0." INDEX { vrrpInstanceIndex, vrrpAddressIndex } ::= { vrrpAddressTable 1 } VrrpAddressEntry ::= SEQUENCE { vrrpAddressIndex Integer32, vrrpAddressType InetAddressType, vrrpAddressValue InetAddress, vrrpAddressBroadcast InetAddress, vrrpAddressMask InetAddressPrefixLength, vrrpAddressScope InetScopeType, vrrpAddressIfIndex InterfaceIndex, vrrpAddressIfName DisplayString, vrrpAddressIfAlias DisplayString, vrrpAddressStatus INTEGER, vrrpAddressAdvertising INTEGER } vrrpAddressIndex OBJECT-TYPE SYNTAX Integer32 (1..2147483647) MAX-ACCESS not-accessible STATUS current DESCRIPTION "Address index." ::= { vrrpAddressEntry 1 } vrrpAddressType OBJECT-TYPE SYNTAX InetAddressType MAX-ACCESS read-only STATUS current DESCRIPTION "A value that represents a type of Internet address." ::= { vrrpAddressEntry 2 } vrrpAddressValue OBJECT-TYPE SYNTAX InetAddress MAX-ACCESS read-only STATUS current DESCRIPTION "Actual IP address." ::= { vrrpAddressEntry 3 } vrrpAddressBroadcast OBJECT-TYPE SYNTAX InetAddress MAX-ACCESS read-only STATUS current DESCRIPTION "Broadcast address associated with the IP address." ::= { vrrpAddressEntry 4 } vrrpAddressMask OBJECT-TYPE SYNTAX InetAddressPrefixLength MAX-ACCESS read-only STATUS current DESCRIPTION "Address mask." ::= { vrrpAddressEntry 5 } vrrpAddressScope OBJECT-TYPE SYNTAX InetScopeType MAX-ACCESS read-only STATUS current DESCRIPTION "Address scope." ::= { vrrpAddressEntry 6 } vrrpAddressIfIndex OBJECT-TYPE SYNTAX InterfaceIndex MAX-ACCESS read-only STATUS current DESCRIPTION "Index of the interface to which the IP address is linked to." ::= { vrrpAddressEntry 7 } vrrpAddressIfName OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Name of the interface to which the IP address is linked to." ::= { vrrpAddressEntry 8 } vrrpAddressIfAlias OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Alias name of the interface." ::= { vrrpAddressEntry 9 } vrrpAddressStatus OBJECT-TYPE SYNTAX INTEGER { set(1), unset(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Is the IP address set?" ::= { vrrpAddressEntry 10 } vrrpAddressAdvertising OBJECT-TYPE SYNTAX INTEGER { advertised(1), notAdvertised(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Status of VRRP advertising for this IP address." ::= { vrrpAddressEntry 11 } -- Routes -- see vrrp_iproute.h vrrpRouteTable OBJECT-TYPE SYNTAX SEQUENCE OF VrrpRouteEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Table of static and virtual routes." ::= { vrrp 7 } vrrpRouteEntry OBJECT-TYPE SYNTAX VrrpRouteEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information describing a route. In case of a static route, the instance index is 0." INDEX { vrrpInstanceIndex, vrrpRouteIndex } ::= { vrrpRouteTable 1 } VrrpRouteEntry ::= SEQUENCE { vrrpRouteIndex Integer32, vrrpRouteAddressType InetAddressType, vrrpRouteDestination InetAddress, vrrpRouteDestinationMask InetAddressPrefixLength, vrrpRouteGateway InetAddress, vrrpRouteSecondaryGateway InetAddress, vrrpRouteSource InetAddress, vrrpRouteMetric Unsigned32, vrrpRouteScope InetScopeType, vrrpRouteType INTEGER, vrrpRouteIfIndex InterfaceIndex, vrrpRouteIfName DisplayString, vrrpRouteRoutingTable Unsigned32, vrrpRouteStatus INTEGER } vrrpRouteIndex OBJECT-TYPE SYNTAX Integer32 (1..2147483647) MAX-ACCESS not-accessible STATUS current DESCRIPTION "Route index." ::= { vrrpRouteEntry 1 } vrrpRouteAddressType OBJECT-TYPE SYNTAX InetAddressType MAX-ACCESS read-only STATUS current DESCRIPTION "Route type of internet address." ::= { vrrpRouteEntry 2 } vrrpRouteDestination OBJECT-TYPE SYNTAX InetAddress MAX-ACCESS read-only STATUS current DESCRIPTION "Route destination." ::= { vrrpRouteEntry 3 } vrrpRouteDestinationMask OBJECT-TYPE SYNTAX InetAddressPrefixLength MAX-ACCESS read-only STATUS current DESCRIPTION "Route destination mask." ::= { vrrpRouteEntry 4 } vrrpRouteGateway OBJECT-TYPE SYNTAX InetAddress MAX-ACCESS read-only STATUS current DESCRIPTION "Gateway for the given destination." ::= { vrrpRouteEntry 5 } vrrpRouteSecondaryGateway OBJECT-TYPE SYNTAX InetAddress MAX-ACCESS read-only STATUS current DESCRIPTION "An optional second gateway for the given destination." ::= { vrrpRouteEntry 6 } vrrpRouteSource OBJECT-TYPE SYNTAX InetAddress MAX-ACCESS read-only STATUS current DESCRIPTION "Which source IP address to use with this route." ::= { vrrpRouteEntry 7 } vrrpRouteMetric OBJECT-TYPE SYNTAX Unsigned32 MAX-ACCESS read-only STATUS current DESCRIPTION "Metric of this route." ::= { vrrpRouteEntry 8 } vrrpRouteScope OBJECT-TYPE SYNTAX InetScopeType MAX-ACCESS read-only STATUS current DESCRIPTION "Scope of this route." ::= { vrrpRouteEntry 9 } vrrpRouteType OBJECT-TYPE SYNTAX INTEGER { normal(1), ecmp(2), blackhole(3) } MAX-ACCESS read-only STATUS current DESCRIPTION "Kind of route." ::= { vrrpRouteEntry 10 } vrrpRouteIfIndex OBJECT-TYPE SYNTAX InterfaceIndex MAX-ACCESS read-only STATUS current DESCRIPTION "Interface attached to this route." ::= { vrrpRouteEntry 11 } vrrpRouteIfName OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Name of the interface of attached to this route." ::= { vrrpRouteEntry 12 } vrrpRouteRoutingTable OBJECT-TYPE SYNTAX Unsigned32 MAX-ACCESS read-only STATUS current DESCRIPTION "Routing table where to route should be inserted." ::= { vrrpRouteEntry 13 } vrrpRouteStatus OBJECT-TYPE SYNTAX INTEGER { set(1), unset(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Is this route set in the kernel?" ::= { vrrpRouteEntry 14 } -- VRRP scripts -- see vrrp_track.h vrrpScriptTable OBJECT-TYPE SYNTAX SEQUENCE OF VrrpScriptEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Table of VRRP scripts" ::= { vrrp 8 } vrrpScriptEntry OBJECT-TYPE SYNTAX VrrpScriptEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information describing a VRRP script" INDEX { vrrpScriptIndex } ::= { vrrpScriptTable 1 } VrrpScriptEntry ::= SEQUENCE { vrrpScriptIndex Integer32, vrrpScriptName DisplayString, vrrpScriptCommand DisplayString, vrrpScriptInterval Integer32, vrrpScriptWeight Integer32, vrrpScriptResult INTEGER, vrrpScriptRise Unsigned32, vrrpScriptFall Unsigned32 } vrrpScriptIndex OBJECT-TYPE SYNTAX Integer32 (1..2147483647) MAX-ACCESS not-accessible STATUS current DESCRIPTION "Script index." ::= { vrrpScriptEntry 1 } vrrpScriptName OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Symbolic name of the script." ::= { vrrpScriptEntry 2 } vrrpScriptCommand OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Command executed when running the script." ::= { vrrpScriptEntry 3 } vrrpScriptInterval OBJECT-TYPE SYNTAX Integer32 UNITS "seconds" MAX-ACCESS read-only STATUS current DESCRIPTION "Interval between two runs of the script." ::= { vrrpScriptEntry 4 } vrrpScriptWeight OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "Weight of the script if successful." ::= { vrrpScriptEntry 5 } vrrpScriptResult OBJECT-TYPE SYNTAX INTEGER { disabled(0), init(1), bad(2), good(3), initgood(4) } MAX-ACCESS read-only STATUS current DESCRIPTION "Current status of the script." ::= { vrrpScriptEntry 6 } vrrpScriptRise OBJECT-TYPE SYNTAX Unsigned32 MAX-ACCESS read-only STATUS current DESCRIPTION "How many times the script should succeed before OK." ::= { vrrpScriptEntry 7 } vrrpScriptFall OBJECT-TYPE SYNTAX Unsigned32 MAX-ACCESS read-only STATUS current DESCRIPTION "How many times the script should fail before KO." ::= { vrrpScriptEntry 8 } -- Traps vrrpTrap OBJECT IDENTIFIER ::= { vrrp 9 } vrrpTraps OBJECT IDENTIFIER ::= { vrrpTrap 0 } -- Reverse-mappable vrrpTrapControl OBJECT IDENTIFIER ::= { vrrpTrap 1 } vrrpSyncGroupStateChange NOTIFICATION-TYPE OBJECTS { vrrpSyncGroupName, vrrpSyncGroupState, routerId } STATUS current DESCRIPTION "This trap signifies that the state of the whole vrrp sync group changed." ::= { vrrpTraps 1 } vrrpInstanceStateChange NOTIFICATION-TYPE OBJECTS { vrrpInstanceName, vrrpInstanceState, vrrpInstanceInitialState, routerId } STATUS current DESCRIPTION "This trap signifies that the state of a vrrp instance changed." ::= { vrrpTraps 2 } -- ---------------------------------------------------------------------- -- Healthchecker part -- ---------------------------------------------------------------------- -- Virtual server group virtualServerGroupTable OBJECT-TYPE SYNTAX SEQUENCE OF VirtualServerGroupEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Table of virtual server groups." ::= { check 1 } virtualServerGroupEntry OBJECT-TYPE SYNTAX VirtualServerGroupEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information describing a virtual server group." INDEX { virtualServerGroupIndex } ::= { virtualServerGroupTable 1 } VirtualServerGroupEntry ::= SEQUENCE { virtualServerGroupIndex Integer32, virtualServerGroupName DisplayString } virtualServerGroupIndex OBJECT-TYPE SYNTAX Integer32 (1..2147483647) MAX-ACCESS not-accessible STATUS current DESCRIPTION "Index of the virtual server group." ::= { virtualServerGroupEntry 1 } virtualServerGroupName OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Name of the virtual server group." ::= { virtualServerGroupEntry 2 } virtualServerGroupMemberTable OBJECT-TYPE SYNTAX SEQUENCE OF VirtualServerGroupMemberEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Table of members of a virtual server group." ::= { check 2 } virtualServerGroupMemberEntry OBJECT-TYPE SYNTAX VirtualServerGroupMemberEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Description of a member of a virtual server group." INDEX { virtualServerGroupIndex, virtualServerGroupMemberIndex } ::= { virtualServerGroupMemberTable 1 } VirtualServerGroupMemberEntry ::= SEQUENCE { virtualServerGroupMemberIndex Integer32, virtualServerGroupMemberType INTEGER, virtualServerGroupMemberFwMark Unsigned32, virtualServerGroupMemberAddrType InetAddressType, virtualServerGroupMemberAddress InetAddress, virtualServerGroupMemberAddr1 InetAddress, virtualServerGroupMemberAddr2 InetAddress, virtualServerGroupMemberPort InetPortNumber } virtualServerGroupMemberIndex OBJECT-TYPE SYNTAX Integer32 (1..2147483647) MAX-ACCESS not-accessible STATUS current DESCRIPTION "Index of the member into virtual server group." ::= { virtualServerGroupMemberEntry 1 } virtualServerGroupMemberType OBJECT-TYPE SYNTAX INTEGER { fwmark(1), ip(2), iprange(3) } MAX-ACCESS read-only STATUS current DESCRIPTION "Kind of entry: firewall mark, address with port or range of addresses with port." ::= { virtualServerGroupMemberEntry 2 } virtualServerGroupMemberFwMark OBJECT-TYPE SYNTAX Unsigned32 MAX-ACCESS read-only STATUS current DESCRIPTION "Firewall mark for this member. If the kind of this member is not fwmark(1), then this entry should not exist for the current row." ::= { virtualServerGroupMemberEntry 3 } virtualServerGroupMemberAddrType OBJECT-TYPE SYNTAX InetAddressType MAX-ACCESS read-only STATUS current DESCRIPTION "Type of IP address for this member. If the kind of this member is neither address(2) or range(3), then this entry should not exist for the current row." ::= { virtualServerGroupMemberEntry 4 } virtualServerGroupMemberAddress OBJECT-TYPE SYNTAX InetAddress MAX-ACCESS read-only STATUS current DESCRIPTION "IP address of this member. If the kind of this member is not address(2), then this entry should not exist for the current row." ::= { virtualServerGroupMemberEntry 5 } virtualServerGroupMemberAddr1 OBJECT-TYPE SYNTAX InetAddress MAX-ACCESS read-only STATUS current DESCRIPTION "First IP address of the range for this member. If the kind of this member is not range(3), then this entry should not exist for the current row." ::= { virtualServerGroupMemberEntry 6 } virtualServerGroupMemberAddr2 OBJECT-TYPE SYNTAX InetAddress MAX-ACCESS read-only STATUS current DESCRIPTION "Second IP address of the range for this member. If the kind of this member is not range(3), then this entry should not exist for the current row." ::= { virtualServerGroupMemberEntry 7 } virtualServerGroupMemberPort OBJECT-TYPE SYNTAX InetPortNumber MAX-ACCESS read-only STATUS current DESCRIPTION "V port for this member. If the kind of this member is neither address(2) nor range(3), then this entry should not exist for the current row." ::= { virtualServerGroupMemberEntry 8 } -- virtual server virtualServerTable OBJECT-TYPE SYNTAX SEQUENCE OF VirtualServerEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Table of virtual servers." ::= { check 3 } virtualServerEntry OBJECT-TYPE SYNTAX VirtualServerEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information describing a virtual server." INDEX { virtualServerIndex } ::= { virtualServerTable 1 } VirtualServerEntry ::= SEQUENCE { virtualServerIndex Integer32, virtualServerType INTEGER, virtualServerNameOfGroup DisplayString, virtualServerFwMark Unsigned32, virtualServerAddrType InetAddressType, virtualServerAddress InetAddress, virtualServerPort InetPortNumber, virtualServerProtocol INTEGER, virtualServerLoadBalancingAlgo INTEGER, virtualServerLoadBalancingKind INTEGER, virtualServerStatus INTEGER, virtualServerVirtualHost DisplayString, virtualServerPersist INTEGER, virtualServerPersistTimeout Unsigned32, virtualServerPersistGranularity InetAddress, virtualServerDelayLoop Unsigned32, virtualServerHaSuspend TruthValue, virtualServerAlpha INTEGER, virtualServerOmega INTEGER, virtualServerRealServersTotal Unsigned32, virtualServerRealServersUp Unsigned32, virtualServerQuorum Unsigned32, virtualServerQuorumStatus INTEGER, virtualServerQuorumUp DisplayString, virtualServerQuorumDown DisplayString, virtualServerHysteresis Unsigned32, virtualServerStatsConns Gauge32, virtualServerStatsInPkts Counter32, virtualServerStatsOutPkts Counter32, virtualServerStatsInBytes Counter64, virtualServerStatsOutBytes Counter64, virtualServerRateCps Gauge32, virtualServerRateInPPS Gauge32, virtualServerRateOutPPS Gauge32, virtualServerRateInBPS Gauge32, virtualServerRateOutBPS Gauge32 } virtualServerIndex OBJECT-TYPE SYNTAX Integer32 (1..2147483647) MAX-ACCESS not-accessible STATUS current DESCRIPTION "Index of the virtual server." ::= { virtualServerEntry 1 } virtualServerType OBJECT-TYPE SYNTAX INTEGER { fwmark(1), ip(2), group(3) } MAX-ACCESS read-only STATUS current DESCRIPTION "Type of virtual server. A virtual server can either be defined from a firewall mark, an IP and a port or from a virtual server group." ::= { virtualServerEntry 2 } virtualServerNameOfGroup OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "If the virtual is defined from a group, this is the name of the group." ::= { virtualServerEntry 3 } virtualServerFwMark OBJECT-TYPE SYNTAX Unsigned32 MAX-ACCESS read-only STATUS current DESCRIPTION "If the virtual server is defined from a firewall mark, this is the value of the mark. Otherwise, this column should not exist in the current row." ::= { virtualServerEntry 4 } virtualServerAddrType OBJECT-TYPE SYNTAX InetAddressType MAX-ACCESS read-only STATUS current DESCRIPTION "If the virtual server is defined from an IP, this is the address family. Otherwise, this column should not exist in the current row." ::= { virtualServerEntry 5 } virtualServerAddress OBJECT-TYPE SYNTAX InetAddress MAX-ACCESS read-only STATUS current DESCRIPTION "If the virtual server is defined from an IP address, this is the value of the IP. Otherwise, this column should not exist in the current row." ::= { virtualServerEntry 6 } virtualServerPort OBJECT-TYPE SYNTAX InetPortNumber MAX-ACCESS read-only STATUS current DESCRIPTION "If the virtual server is defined from an IP, this is the value of the port to listen for requests. Otherwise, this column should not exist in the current row." ::= { virtualServerEntry 7 } virtualServerProtocol OBJECT-TYPE SYNTAX INTEGER { tcp(1), udp(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Which transport protocol should be used for this virtual server." ::= { virtualServerEntry 8 } virtualServerLoadBalancingAlgo OBJECT-TYPE SYNTAX INTEGER { rr(1), wrr(2), lc(3), wlc(4), lblc(5), lblcr(6), dh(7), sh(8), sed(9), nq(10), unknown(99) } MAX-ACCESS read-only STATUS current DESCRIPTION "Which load balancing algorithm (or scheduler) should be used for this virtual server." ::= { virtualServerEntry 9 } virtualServerLoadBalancingKind OBJECT-TYPE SYNTAX INTEGER { nat(1), dr(2), tun(3) } MAX-ACCESS read-only STATUS current DESCRIPTION "Forwarding method to use for this virtual server." ::= { virtualServerEntry 10 } virtualServerStatus OBJECT-TYPE SYNTAX INTEGER { alive(1), dead(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Current status of this virtual server." ::= { virtualServerEntry 11 } virtualServerVirtualHost OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Virtualhost of this server for HTTP like requests." ::= { virtualServerEntry 12 } virtualServerPersist OBJECT-TYPE SYNTAX INTEGER { enabled(1), disabled(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Is the virtual service persistence enabled?" ::= { virtualServerEntry 13 } virtualServerPersistTimeout OBJECT-TYPE SYNTAX Unsigned32 UNITS "seconds" MAX-ACCESS read-only STATUS current DESCRIPTION "If this virtual service is persistence, what is the timeout." ::= { virtualServerEntry 14 } virtualServerPersistGranularity OBJECT-TYPE SYNTAX InetAddress MAX-ACCESS read-only STATUS current DESCRIPTION "Netmask specifying the granularity of the persistence mechanism." ::= { virtualServerEntry 15 } virtualServerDelayLoop OBJECT-TYPE SYNTAX Unsigned32 UNITS "seconds" MAX-ACCESS read-only STATUS current DESCRIPTION "Delay in seconds between two checks." ::= { virtualServerEntry 16 } virtualServerHaSuspend OBJECT-TYPE SYNTAX TruthValue MAX-ACCESS read-only STATUS current DESCRIPTION "If set to true(1), checks will be suspended if the IP of the virtual server is currently not set." ::= { virtualServerEntry 17 } virtualServerAlpha OBJECT-TYPE SYNTAX INTEGER { enabled(1), disabled(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Is alpha mode enabled?" ::= { virtualServerEntry 18 } virtualServerOmega OBJECT-TYPE SYNTAX INTEGER { enabled(1), disabled(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Is omega mode enabled?" ::= { virtualServerEntry 19 } virtualServerRealServersTotal OBJECT-TYPE SYNTAX Unsigned32 MAX-ACCESS read-only STATUS current DESCRIPTION "Total number of real servers for this virtual server." ::= { virtualServerEntry 20 } virtualServerRealServersUp OBJECT-TYPE SYNTAX Unsigned32 MAX-ACCESS read-only STATUS current DESCRIPTION "Real servers actually up for this virtual server." ::= { virtualServerEntry 21 } virtualServerQuorum OBJECT-TYPE SYNTAX Unsigned32 MAX-ACCESS read-only STATUS current DESCRIPTION "Quorum to get amond real servers to consider this virtual server up." ::= { virtualServerEntry 22 } virtualServerQuorumStatus OBJECT-TYPE SYNTAX INTEGER { met(1), notMet(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Current status of the quorum for this virtual server." ::= { virtualServerEntry 23 } virtualServerQuorumUp OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Command to execute when the quorum is met." ::= { virtualServerEntry 24 } virtualServerQuorumDown OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Command to execute when the quorum is not met." ::= { virtualServerEntry 25 } virtualServerHysteresis OBJECT-TYPE SYNTAX Unsigned32 MAX-ACCESS read-only STATUS current DESCRIPTION "Hysteresis with respect to quorum count." ::= { virtualServerEntry 26 } virtualServerStatsConns OBJECT-TYPE SYNTAX Gauge32 UNITS "connections" MAX-ACCESS read-only STATUS current DESCRIPTION "Total number of connections scheduled for this virtual server." ::= { virtualServerEntry 27 } virtualServerStatsInPkts OBJECT-TYPE SYNTAX Counter32 UNITS "packets" MAX-ACCESS read-only STATUS current DESCRIPTION "Total number of incoming packets for this virtual server." ::= { virtualServerEntry 28 } virtualServerStatsOutPkts OBJECT-TYPE SYNTAX Counter32 UNITS "packets" MAX-ACCESS read-only STATUS current DESCRIPTION "Total number of outgoing packets for this virtual server." ::= { virtualServerEntry 29 } virtualServerStatsInBytes OBJECT-TYPE SYNTAX Counter64 UNITS "bytes" MAX-ACCESS read-only STATUS current DESCRIPTION "Total number of incoming bytes for this virtual server." ::= { virtualServerEntry 30 } virtualServerStatsOutBytes OBJECT-TYPE SYNTAX Counter64 UNITS "bytes" MAX-ACCESS read-only STATUS current DESCRIPTION "Total number of outgoing bytes for this virtual server." ::= { virtualServerEntry 31 } virtualServerRateCps OBJECT-TYPE SYNTAX Gauge32 UNITS "connections/s" MAX-ACCESS read-only STATUS current DESCRIPTION "Current connection rate for this virtual server." ::= { virtualServerEntry 32 } virtualServerRateInPPS OBJECT-TYPE SYNTAX Gauge32 UNITS "packets/s" MAX-ACCESS read-only STATUS current DESCRIPTION "Current in packet rate for this virtual server." ::= { virtualServerEntry 33 } virtualServerRateOutPPS OBJECT-TYPE SYNTAX Gauge32 UNITS "packets/s" MAX-ACCESS read-only STATUS current DESCRIPTION "Current out packet rate for this virtual server." ::= { virtualServerEntry 34 } virtualServerRateInBPS OBJECT-TYPE SYNTAX Gauge32 UNITS "bytes/s" MAX-ACCESS read-only STATUS current DESCRIPTION "Current incoming rate for this virtual server." ::= { virtualServerEntry 35 } virtualServerRateOutBPS OBJECT-TYPE SYNTAX Gauge32 UNITS "bytes/s" MAX-ACCESS read-only STATUS current DESCRIPTION "Current outgoing rate for this virtual server." ::= { virtualServerEntry 36 } -- real servers realServerTable OBJECT-TYPE SYNTAX SEQUENCE OF RealServerEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Table of real servers. This includes regular real servers and sorry servers." ::= { check 4 } realServerEntry OBJECT-TYPE SYNTAX RealServerEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information describing a real server." INDEX { virtualServerIndex, realServerIndex } ::= { realServerTable 1 } RealServerEntry ::= SEQUENCE { realServerIndex Integer32, realServerType INTEGER, realServerAddrType InetAddressType, realServerAddress InetAddress, realServerPort InetPortNumber, realServerStatus INTEGER, realServerWeight Integer32, realServerUpperConnectionLimit Unsigned32, realServerLowerConnectionLimit Unsigned32, realServerActionWhenDown INTEGER, realServerNotifyUp DisplayString, realServerNotifyDown DisplayString, realServerFailedChecks Unsigned32, realServerStatsConns Gauge32, realServerStatsActiveConns Gauge32, realServerStatsInactiveConns Gauge32, realServerStatsPersistentConns Gauge32, realServerStatsInPkts Counter32, realServerStatsOutPkts Counter32, realServerStatsInBytes Counter64, realServerStatsOutBytes Counter64, realServerRateCps Gauge32, realServerRateInPPS Gauge32, realServerRateOutPPS Gauge32, realServerRateInBPS Gauge32, realServerRateOutBPS Gauge32 } realServerIndex OBJECT-TYPE SYNTAX Integer32 (1..2147483647) MAX-ACCESS not-accessible STATUS current DESCRIPTION "Index of the real server." ::= { realServerEntry 1 } realServerType OBJECT-TYPE SYNTAX INTEGER { regular(1), sorry(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Type of real server: either a regular real server or a sorry server." ::= { realServerEntry 2 } realServerAddrType OBJECT-TYPE SYNTAX InetAddressType MAX-ACCESS read-only STATUS current DESCRIPTION "Address family for this real server." ::= { realServerEntry 3 } realServerAddress OBJECT-TYPE SYNTAX InetAddress MAX-ACCESS read-only STATUS current DESCRIPTION "IP address of this real server." ::= { realServerEntry 4 } realServerPort OBJECT-TYPE SYNTAX InetPortNumber MAX-ACCESS read-only STATUS current DESCRIPTION "Port of the service." ::= { realServerEntry 5 } realServerStatus OBJECT-TYPE SYNTAX INTEGER { alive(1), dead(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Status of this real server." ::= { realServerEntry 6 } realServerWeight OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-write STATUS current DESCRIPTION "Weight of this real server. This value can be set to 0 to disable the real server." ::= { realServerEntry 7 } realServerUpperConnectionLimit OBJECT-TYPE SYNTAX Unsigned32 MAX-ACCESS read-only STATUS current DESCRIPTION "Maximum number of connections for this real server." ::= { realServerEntry 8 } realServerLowerConnectionLimit OBJECT-TYPE SYNTAX Unsigned32 MAX-ACCESS read-only STATUS current DESCRIPTION "Minimum number of connections for this real server." ::= { realServerEntry 9 } realServerActionWhenDown OBJECT-TYPE SYNTAX INTEGER { remove(1), inhibit(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "What action is performed when this server is down. Its weight can be set to 0 (inhibit) or it can be removed from the pool." ::= { realServerEntry 10 } realServerNotifyUp OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Command to execute when this server becomes alive." ::= { realServerEntry 11 } realServerNotifyDown OBJECT-TYPE SYNTAX DisplayString MAX-ACCESS read-only STATUS current DESCRIPTION "Command to execute when this server becomes dead." ::= { realServerEntry 12 } realServerFailedChecks OBJECT-TYPE SYNTAX Unsigned32 MAX-ACCESS read-only STATUS current DESCRIPTION "How many failed checks for this real server." ::= { realServerEntry 13 } realServerStatsConns OBJECT-TYPE SYNTAX Gauge32 UNITS "connections" MAX-ACCESS read-only STATUS current DESCRIPTION "Total number of connections scheduled for this real server." ::= { realServerEntry 14 } realServerStatsActiveConns OBJECT-TYPE SYNTAX Gauge32 UNITS "connections" MAX-ACCESS read-only STATUS current DESCRIPTION "Current active connections for this real server." ::= { realServerEntry 15 } realServerStatsInactiveConns OBJECT-TYPE SYNTAX Gauge32 UNITS "connections" MAX-ACCESS read-only STATUS current DESCRIPTION "Current inactive connections for this real server." ::= { realServerEntry 16 } realServerStatsPersistentConns OBJECT-TYPE SYNTAX Gauge32 UNITS "connections" MAX-ACCESS read-only STATUS current DESCRIPTION "Current persistent connections for this real server." ::= { realServerEntry 17 } realServerStatsInPkts OBJECT-TYPE SYNTAX Counter32 UNITS "packets" MAX-ACCESS read-only STATUS current DESCRIPTION "Total number of incoming packets for this real server." ::= { realServerEntry 18 } realServerStatsOutPkts OBJECT-TYPE SYNTAX Counter32 UNITS "packets" MAX-ACCESS read-only STATUS current DESCRIPTION "Total number of outgoing packets for this real server." ::= { realServerEntry 19 } realServerStatsInBytes OBJECT-TYPE SYNTAX Counter64 UNITS "bytes" MAX-ACCESS read-only STATUS current DESCRIPTION "Total number of incoming bytes for this real server." ::= { realServerEntry 20 } realServerStatsOutBytes OBJECT-TYPE SYNTAX Counter64 UNITS "bytes" MAX-ACCESS read-only STATUS current DESCRIPTION "Total number of outgoing bytes for this real server." ::= { realServerEntry 21 } realServerRateCps OBJECT-TYPE SYNTAX Gauge32 UNITS "connections/s" MAX-ACCESS read-only STATUS current DESCRIPTION "Current connection rate for this real server." ::= { realServerEntry 22 } realServerRateInPPS OBJECT-TYPE SYNTAX Gauge32 UNITS "packets/s" MAX-ACCESS read-only STATUS current DESCRIPTION "Current in packet rate for this real server." ::= { realServerEntry 23 } realServerRateOutPPS OBJECT-TYPE SYNTAX Gauge32 UNITS "packets/s" MAX-ACCESS read-only STATUS current DESCRIPTION "Current out packet rate for this real server." ::= { realServerEntry 24 } realServerRateInBPS OBJECT-TYPE SYNTAX Gauge32 UNITS "bytes/s" MAX-ACCESS read-only STATUS current DESCRIPTION "Current incoming rate for this real server." ::= { realServerEntry 25 } realServerRateOutBPS OBJECT-TYPE SYNTAX Gauge32 UNITS "bytes/s" MAX-ACCESS read-only STATUS current DESCRIPTION "Current outgoing rate for this real server." ::= { realServerEntry 26 } -- Traps checkTrap OBJECT IDENTIFIER ::= { check 5 } checkTraps OBJECT IDENTIFIER ::= { checkTrap 0 } -- Reverse-mappable checkTrapControl OBJECT IDENTIFIER ::= { checkTrap 1 } realServerStateChange NOTIFICATION-TYPE OBJECTS { realServerAddrType, realServerAddress, realServerPort, realServerStatus, virtualServerType, virtualServerProtocol, virtualServerRealServersUp, virtualServerRealServersTotal, routerId } STATUS current DESCRIPTION "This trap signifies that the state of a real server has changed. Additional varbinds will be added depending on the value of virtualServerType: virtualServerNameOfGroup, virtualServerFwMark, virtualServerAddrType, virtualServerAddress, virtualServerPort." ::= { checkTraps 1 } virtualServerQuorumStateChange NOTIFICATION-TYPE OBJECTS { virtualServerType, virtualServerProtocol, virtualServerQuorumStatus, virtualServerQuorum, virtualServerRealServersUp, virtualServerRealServersTotal, routerId } STATUS current DESCRIPTION "This trap signifies that the quorum of a virtual server has changed. Additional varbinds will be added depending on the value of virtualServerType: virtualServerNameOfGroup, virtualServerFwMark, virtualServerAddrType, virtualServerAddress, virtualServerPort." ::= { checkTraps 2 } -- ---------------------------------------------------------------------- -- Conformance -- ---------------------------------------------------------------------- compliances OBJECT IDENTIFIER ::= { conformance 1 } groups OBJECT IDENTIFIER ::= { conformance 2 } globalCompliances MODULE-COMPLIANCE STATUS current DESCRIPTION "Compliance statement for global data" MODULE -- this module MANDATORY-GROUPS { globalGroup } ::= { compliances 1 } vrrpCompliances MODULE-COMPLIANCE STATUS current DESCRIPTION "The VRRP compliance statement" MODULE -- this module MANDATORY-GROUPS { vrrpScriptGroup, vrrpSyncGroup, vrrpInstanceGroup, vrrpTrapsGroup } ::= { compliances 2 } checkCompliances MODULE-COMPLIANCE STATUS current DESCRIPTION "The check compliance statement" MODULE -- this module MANDATORY-GROUPS { virtualServerGroupGroup, virtualServerGroup, realServerGroup, checkTrapsGroup } ::= { compliances 3 } globalGroup OBJECT-GROUP OBJECTS { version, routerId, smtpServerAddressType, smtpServerAddress, smtpServerTimeout, emailFrom, emailAddress, trapEnable, linkBeat } STATUS current DESCRIPTION "Conformance group for global data." ::= { groups 1 } vrrpGroups OBJECT IDENTIFIER ::= { groups 2 } vrrpSyncGroup OBJECT-GROUP OBJECTS { vrrpSyncGroupName, vrrpSyncGroupState, vrrpSyncGroupSmtpAlert, vrrpSyncGroupNotifyExec, vrrpSyncGroupScriptMaster, vrrpSyncGroupScriptBackup, vrrpSyncGroupScriptFault, vrrpSyncGroupScript, vrrpSyncGroupMemberName } STATUS current DESCRIPTION "Conformance group for synchronisation groups." ::= { vrrpGroups 1 } vrrpInstanceGroup OBJECT-GROUP OBJECTS { vrrpInstanceName, vrrpInstanceVirtualRouterId, vrrpInstanceState, vrrpInstanceInitialState, vrrpInstanceWantedState, vrrpInstanceBasePriority, vrrpInstanceEffectivePriority, vrrpInstanceVipsStatus, vrrpInstancePrimaryInterface, vrrpInstanceTrackPrimaryIf, vrrpInstanceAdvertisementsInt, vrrpInstancePreempt, vrrpInstancePreemptDelay, vrrpInstanceAuthType, vrrpInstanceLvsSyncDaemon, vrrpInstanceLvsSyncInterface, vrrpInstanceSyncGroup, vrrpInstanceGarpDelay, vrrpInstanceSmtpAlert, vrrpInstanceNotifyExec, vrrpInstanceScriptMaster, vrrpInstanceScriptBackup, vrrpInstanceScriptFault, vrrpInstanceScriptStop, vrrpInstanceScript, vrrpTrackedInterfaceName, vrrpTrackedInterfaceWeight, vrrpTrackedScriptName, vrrpTrackedScriptWeight, vrrpAddressType, vrrpAddressValue, vrrpAddressBroadcast, vrrpAddressMask, vrrpAddressScope, vrrpAddressIfIndex, vrrpAddressIfName, vrrpAddressIfAlias, vrrpAddressStatus, vrrpAddressAdvertising, vrrpRouteAddressType, vrrpRouteDestination, vrrpRouteDestinationMask, vrrpRouteGateway, vrrpRouteSecondaryGateway, vrrpRouteSource, vrrpRouteMetric, vrrpRouteScope, vrrpRouteType, vrrpRouteIfIndex, vrrpRouteIfName, vrrpRouteRoutingTable, vrrpRouteStatus } STATUS current DESCRIPTION "Conformance group for VRRP instances." ::= { vrrpGroups 2 } vrrpScriptGroup OBJECT-GROUP OBJECTS { vrrpScriptName, vrrpScriptCommand, vrrpScriptInterval, vrrpScriptWeight, vrrpScriptResult, vrrpScriptRise, vrrpScriptFall } STATUS current DESCRIPTION "Conformance group for VRRP scripts." ::= { vrrpGroups 3 } vrrpTrapsGroup NOTIFICATION-GROUP NOTIFICATIONS { vrrpSyncGroupStateChange, vrrpInstanceStateChange } STATUS current DESCRIPTION "Conformance group for VRRP traps." ::= { vrrpGroups 4 } checkGroups OBJECT IDENTIFIER ::= { groups 3 } virtualServerGroupGroup OBJECT-GROUP OBJECTS { virtualServerGroupName, virtualServerGroupMemberType, virtualServerGroupMemberFwMark, virtualServerGroupMemberAddrType, virtualServerGroupMemberAddress, virtualServerGroupMemberAddr1, virtualServerGroupMemberAddr2, virtualServerGroupMemberPort } STATUS current DESCRIPTION "Conformance group for virtual server groups." ::= { checkGroups 1 } virtualServerGroup OBJECT-GROUP OBJECTS { virtualServerType, virtualServerNameOfGroup, virtualServerFwMark, virtualServerAddrType, virtualServerAddress, virtualServerPort, virtualServerProtocol, virtualServerLoadBalancingAlgo, virtualServerLoadBalancingKind, virtualServerStatus, virtualServerVirtualHost, virtualServerPersist, virtualServerPersistTimeout, virtualServerPersistGranularity, virtualServerDelayLoop, virtualServerHaSuspend, virtualServerAlpha, virtualServerOmega, virtualServerRealServersTotal, virtualServerRealServersUp, virtualServerQuorum, virtualServerQuorumStatus, virtualServerQuorumUp, virtualServerQuorumDown, virtualServerHysteresis, virtualServerStatsConns, virtualServerStatsInPkts, virtualServerStatsOutPkts, virtualServerStatsInBytes, virtualServerStatsOutBytes, virtualServerRateCps, virtualServerRateInPPS, virtualServerRateOutPPS, virtualServerRateInBPS, virtualServerRateOutBPS } STATUS current DESCRIPTION "Conformance group for virtual servers." ::= { checkGroups 2 } realServerGroup OBJECT-GROUP OBJECTS { realServerType, realServerAddrType, realServerAddress, realServerPort, realServerStatus, realServerWeight, realServerUpperConnectionLimit, realServerLowerConnectionLimit, realServerActionWhenDown, realServerNotifyUp, realServerNotifyDown, realServerFailedChecks, realServerStatsConns, realServerStatsActiveConns, realServerStatsInactiveConns, realServerStatsPersistentConns, realServerStatsInPkts, realServerStatsOutPkts, realServerStatsInBytes, realServerStatsOutBytes, realServerRateCps, realServerRateInPPS, realServerRateOutPPS, realServerRateInBPS, realServerRateOutBPS } STATUS current DESCRIPTION "Conformance group for real servers." ::= { checkGroups 3 } checkTrapsGroup NOTIFICATION-GROUP NOTIFICATIONS { realServerStateChange, virtualServerQuorumStateChange } STATUS current DESCRIPTION "Conformance group for check traps." ::= { checkGroups 4 } END keepalived-1.2.7/doc/keepalived.conf.SYNOPSIS0000664000175000017500000003553612001612654020474 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 } 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 3 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") $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 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 lvs_sync_daemon_interface # Binding interface for lvs syncd garp_master_delay # delay for gratuitous ARP after MASTER # state transition 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