# l7directord
# Linux Director Daemon - run "perldoc l7directord" for details
#
-# 2005-2008 (C) NTT COMWARE
+# Copyright (C) 2005-2010 NTT COMWARE Corporation.
#
# License: GNU General Public License (GPL)
#
# Add custom healthcheck.
# (checktype=custom, customcheck=exec_command)
# - 2009/02/14 NTT COMWARE
+# 3.0.0-1: Add code related to l7vsd v3.0.0. See below.
+# - Add accesslog option.
+# - Add tproxy option.
+# 3.0.4-1: Change module check rule. Allow module name
+# [a-z]+.
+# 3.1.0-1: Add code related to l7vsd v3.1.0. See below.
+# - Add session_thread_pool_size option.
+#
use 5.006;
use strict;
use Socket6;
# current version
-our $VERSION = '3.0.0-0';
-our $COPYRIGHT = 'Copyright (C) 2009 NTT COMWARE CORPORATION';
+our $VERSION = '3.1.0-1';
+our $COPYRIGHT = 'Copyright (C) 2012 NTT COMWARE CORPORATION';
# default global config values
our %GLOBAL = (
maxconn => 0,
qosup => 0,
qosdown => 0,
- sorryserver => { ip => '0.0.0.0', port => 0 },
+ sorryserver => { ip => '0.0.0.0', port => 0, forward => 'none' },
request => undef,
receive => undef,
httpmethod => 'GET',
accesslog_rotate_max_filesize => undef,
accesslog_rotate_rotation_timing => undef,
accesslog_rotate_rotation_timing_value => undef,
+ session_thread_pool_size => undef,
other_virtual_key => undef,
# can override
checkcount => undef,
}
}
elsif ($name eq 'scheduler') {
- my $valid_scheduler = qr{lc|rr|wrr};
- $value = lc $value;
- if (!defined $value || $value !~ /^(?:$valid_scheduler)$/) {
+ if ( $value =~ /[^a-z]/ ) {
config_error($line, 'ERR0105', $config);
}
}
|| $name eq 'accesslog') {
$value = defined $value && $value =~ /^yes$/i ? 1
: defined $value && $value =~ /^no$/i ? 0
- : undef
+ : undef
;
if (!defined $value) {
config_error($line, 'ERR0102', $config);
}
}
elsif ($name eq 'module') {
- ## V3 Un-offering (url,pfileter).
- my %key_option = ( url => ['--pattern-match', '--uri-pattern-match', '--host-pattern-match'],
- sessionless => [],
- ip => [],
- sslid => [],
- );
my $module = undef;
my $option = undef;
- my $key = q{};
+ my $key = q{};
if (defined $value) {
- $value =~ s/["']//g;
($module, $option) = split /\s+/, $value, 2;
}
- $module = lc $module;
- if ( !defined $module || !exists $key_option{$module} ) {
+ if ( $module =~ /[^a-z]/ ) {
config_error($line, 'ERR0111', $config);
}
- for my $key_opt ( @{$key_option{$module}} ) {
- if (defined $option && $option =~ /$key_opt\s+(\S+)/) {
- $key .= q{ } if $key;
- $key .= $key_opt . q{ } . $1;
- }
- }
- if ( !$key && @{$key_option{$module}} ) {
- # when omit cookie module key option
- my $key_opt = join q{' or `}, @{$key_option{$module}};
- config_error($line, 'ERR0112', $module, $key_opt, $config);
- }
$value = {name => $module, option => $option, key => $key};
}
elsif ($name eq 'sorryserver') {
+ my $forward = 'masq';
+ if ($value =~ /^(\S+)\s+(\S+)/) {
+ $value = $1;
+ $forward = lc $2;
+ }
my $sorry_server = ld_gethostservbyname($value, 'tcp');
if (!defined $sorry_server) {
config_error($line, 'ERR0114', $config);
}
+ if ($forward && $forward !~ /^(?:masq|tproxy)$/) {
+ config_error($line, 'ERR0107', $config);
+ }
+ $sorry_server->{forward} = $forward;
$value = $sorry_server;
}
elsif ( $name eq 'qosup'
}
elsif ( $name eq 'socketoption') {
$value = lc $value;
- # socketoption=OPTION,OPTION,OPTION
+ $value =~ s/ //g;
if (!defined $value) {
config_error($line, 'ERR0124', $config);
}
my @option_value = split /,/, $value;
- # OPTION:deferaccept,nodelay,cork,quickackon|quickackoff
+ # OPTION:transparent,deferaccept,nodelay,cork,quickackon|quickackoff
for my $option (@option_value) {
- if($option !~ /^deferaccept|nodelay|cork|quickackon|quickackoff$/) {
+ $option =~ s/ //g;
+ if($option !~ /^transparent|deferaccept|nodelay|cork|quickackon|quickackoff$/) {
config_error($line, 'ERR0124', $config);
}
}
}
elsif ($name eq 'accesslog_rotate_rotation_timing_value') {
my $check = undef;
- $value =~ s/["']//g;
if (!defined $value ) {
config_error($line, 'ERR0129', $config);
}
config_error($line, 'ERR0129', $config);
}
}
+ elsif ($name eq 'session_thread_pool_size') {
+ if (!defined $value || $value !~ /^\d+$/ || $value == 0 ) {
+ config_error($line, 'ERR0101', $config);
+ }
+ }
}
return ($name, $value);
# Parse a fallback server
# pre: line: line number fallback server was read from
# fallback: Should be of the form
-# ip_address|hostname[:port|:service_name] masq
+# ip_address|hostname[:port|:service_name] [masq|tproxy]
# config_line: line read from configuration file
# post: fallback is parsed
# return: Reference to hash of the form
if ( !defined $ip_port ) {
config_error($line, 'ERR0114', $config_line);
}
- if (defined $forward && $forward !~ /^masq$/i) {
+ if (defined $forward && $forward !~ /^(?:masq|tproxy)$/i) {
config_error($line, 'ERR0107', $config_line);
}
my %fallback = %REAL;
$fallback{server} = $ip_port;
- if (defined $forward) {
- $fallback{forward} = $forward;
- }
+ $fallback{option}{forward} = get_forward_flag($forward);
return \%fallback;
}
# Parse a real server
# pre: line: line number real server was read from
# real: Should be of the form
-# ip_address|hostname[:port|:service_name] masq
+# ip_address|hostname[:port|:service_name] [masq|tproxy]
# config_line: line read from configuration file
# post: real is parsed
# return: Reference to array include real server hash reference
my %real = %REAL;
if (defined $forward) {
$forward = lc $forward;
- if ($forward !~ /^masq$/) {
+ if ($forward !~ /^(?:masq|tproxy)$/) {
config_error($line, 'ERR0107', $config_line);
}
$real{forward} = $forward;
if ( defined $v->{sorryserver} && defined $v->{sorryserver}{ip} && defined $v->{sorryserver}{port} ) {
$v->{option}{flags} .= ' -b ' . $v->{sorryserver}{ip} . ':' . $v->{sorryserver}{port};
}
+ if ( defined $v->{sorryserver}{forward} ) {
+ $v->{option}{flags} .= ' ' . get_forward_flag( $v->{sorryserver}{forward} );
+ }
if ( defined $v->{qosup} ) {
$v->{option}{flags} .= ' -Q ' . $v->{qosup};
}
if ( $option_key_flag == 0 ) {
$v->{other_virtual_key} .= ' none';
}
+ if ( defined $v->{session_thread_pool_size} ) {
+ $v->{option}{flags} .= ' --session-thread-pool-size ' . $v->{session_thread_pool_size};
+ }
}
if ( !defined $v->{fallback} && defined $CONFIG{fallback} ) {
}
if ( defined $v->{fallback} ) {
for my $proto ( keys %{ $v->{fallback} } ) {
- $v->{fallback}{$proto}{option}{flags} = '-r ' . get_ip_port( $v->{fallback}{$proto} );
+ $v->{fallback}{$proto}{option}{flags} = '-r ' . get_ip_port( $v->{fallback}{$proto} )
+ . ' ' . $v->{fallback}{$proto}{option}{forward};
}
}
if (defined $v->{checktype} && $v->{checktype} =~ /^\d+$/) {
$r->{server}{port} = $v->{server}{port};
}
- $r->{option}{flags} = '-r ' . get_ip_port($r);
+ $r->{option}{flags} = '-r ' . get_ip_port($r) . ' ' . $r->{option}{forward};
# build request URL
if ( defined $v->{service} && defined $r->{server} ) {
}
if (defined $CONFIG{fallback}) {
- $CONFIG{fallback}{tcp}{option}{flags} = '-r ' . get_ip_port( $CONFIG{fallback}{tcp} );
+ $CONFIG{fallback}{tcp}{option}{flags} = '-r ' . get_ip_port( $CONFIG{fallback}{tcp} )
+ . ' ' . $CONFIG{fallback}{tcp}{option}{forward};
}
}
#
# rip_address: IP address of real server
# rport: Port of real server
-# forwarding_mechanism: Forwarding mechanism for real server. This would be only masq.
+# forwarding_mechanism: Forwarding mechanism for real server.(masq or tproxy)
# weight: Weight of real server
#
# pre: none
$module_key .= q{ } . $v->{module}{key};
}
if ($result == 0) {
- ld_log( _message($success_code, get_ip_port($r), get_ip_port($v), $module_key, $weight) );
+ ld_log( _message($success_code, get_ip_port($r), $r->{forward}, get_ip_port($v), $module_key, $weight) );
}
else {
($output) = split /\n/, $output, 2;
- ld_log( _message($error_code, get_ip_port($r), get_ip_port($v), $module_key, $output) );
+ ld_log( _message($error_code, get_ip_port($r), $r->{forward}, get_ip_port($v), $module_key, $output) );
}
}
my $service_status = &$health_check_func($v, $r);
if ($service_status == $SERVICE_DOWN) {
+ undef $r->{num_connects};
if (!defined $current_status || $current_status == $SERVICE_UP) {
$r->{fail_counts}++;
- undef $r->{num_connects};
if ($r->{fail_counts} >= $v->{checkcount}) {
ld_log( _message( 'ERR0602', get_ip_port($r) ) );
service_set($v_r_list, 'down');
$status_line = $res->status_line;
$status_line =~ s/[\r\n]//g;
+ my $response = $v->{httpmethod} eq "HEAD" ? $res->as_string : $res->content;
my $recstr = $r->{receive};
if (!$res->is_success) {
ld_log( _message( 'WRN1102', $status_line, $r->{server}{ip}, $port ) ) if (!defined $status || $status eq $SERVICE_UP);
return $SERVICE_DOWN;
}
- elsif (defined $recstr && $res->as_string !~ /$recstr/) {
+ elsif (defined $recstr && $response !~ /$recstr/) {
ld_log( _message( 'WRN1103', $recstr, $r->{server}{ip}, $port ) ) if (!defined $status || $status eq $SERVICE_UP);
- ld_debug(3, "Headers " . $res->headers->as_string);
+ ld_debug(3, "HTTP Response " . $response);
ld_debug(2, "check_http: $r->{url} is down\n");
return $SERVICE_DOWN;
}
ld_debug(2, $message);
chomp $message;
- if ( !$PROC_STAT{log_opened} ) {
+ if ( !$CONFIG{supervised} && !$PROC_STAT{log_opened} ) {
return 1;
}
# get_forward_flag
# Get the l7vsadm flag corresponging to a forwarding mechanism
-# pre: forward: Name of forwarding mechanism.
-# Should be masq
+# pre: forward: Name of forwarding mechanism. (masq or tproxy)
# post: none
# return: l7vsadm flag corresponding to the forwading mechanism
# " " if $forward is unknown
my $forward = shift;
if (defined $forward && $forward =~ /^masq$/i) {
- return '-m';
+ return '--masq';
+ }
+ elsif (defined $forward && $forward =~ /^tproxy$/i) {
+ return '--tproxy';
}
return q{};
}
ERR0103 => "Invalid value (set any word) `%s'.",
ERR0104 => "Invalid value (set `custom', `connect', `negotiate', `ping', `off', `on' "
. "or positive number) `%s'.",
- ERR0105 => "Invalid value (set `lc', `rr' or `wrr') `%s'.",
+ ERR0105 => "Invalid schedule module (should be only lowercase letters (a-z)) `%s'.",
ERR0106 => "Invalid value (set `http', `https', `ftp', `smtp', `pop', `imap', "
. "`ldap', `nntp', `dns', `mysql', `pgsql', `sip', or `none') `%s'.",
- ERR0107 => "Invalid value (forwarding mode must be `masq') `%s'.",
+ ERR0107 => "Invalid value (forwarding mode must be `masq' or `tproxy') `%s'.",
ERR0108 => "Invalid port number `%s'.",
ERR0109 => "Invalid protocol (protocol must be `tcp') `%s'.",
ERR0110 => "Invalid HTTP method (set `GET' or `HEAD') `%s'.",
- ERR0111 => "Invalid module (set `url', `pfilter', `ip', `sslid' or `sessionless') `%s'.",
- # ERR0111 => "Invalid module (set `cinsert', `cpassive', `crewrite', `url', `pfilter', `ip', `sslid' or `sessionless') `%s'.",
+ ERR0111 => "Invalid protocol module (should be only lowercase letters (a-z)) `%s'.",
ERR0112 => "Invalid module key option (`%s' module must set `%s' option) `%s'.",
ERR0113 => "Invalid QoS value (set 0 or 1-999[KMG]. must specify unit(KMG)) `%s'.",
ERR0114 => "Invalid address `%s'.",
ERR0201 => "Failed to add virtual service to l7vsd: `%s %s', output: `%s'",
ERR0202 => "Failed to edit virtual service on l7vsd: `%s %s', output: `%s'",
ERR0203 => "Failed to delete virtual service from l7vsd: `%s %s', output: `%s'",
- ERR0204 => "Failed to add server to l7vsd: `%s' ( x `%s %s'), output: `%s'",
- ERR0205 => "Failed to edit server on l7vsd: `%s' ( x `%s %s'), output: `%s'",
- ERR0206 => "Failed to delete server from l7vsd: `%s' ( x `%s %s'), output: `%s'",
+ ERR0204 => "Failed to add server to l7vsd: `%s %s' ( x `%s %s'), output: `%s'",
+ ERR0205 => "Failed to edit server on l7vsd: `%s %s' ( x `%s %s'), output: `%s'",
+ ERR0206 => "Failed to delete server from l7vsd: `%s %s' ( x `%s %s'), output: `%s'",
ERR0207 => "Trying add server `%s', but virtual service `%s' is not found.",
ERR0208 => "Trying delete server `%s', but virtual service `%s' is not found.",
ERR0209 => "`%s' was already existed on l7vsd. ( x `%s %s')",
INF0201 => "Add virtual service to l7vsd: `%s %s'",
INF0202 => "Edit virtual service on l7vsd: `%s %s'",
INF0203 => "Delete virtual service from l7vsd: `%s %s'",
- INF0204 => "Add server to l7vsd: `%s' ( x `%s %s') (weight set to %d)",
- INF0205 => "Edit server on l7vsd: `%s' ( x `%s %s') (weight set to %d)",
- INF0206 => "Delete server from l7vsd: `%s' ( x `%s %s')",
+ INF0204 => "Add server to l7vsd: `%s %s' ( x `%s %s') (weight set to %d)",
+ INF0205 => "Edit server on l7vsd: `%s %s' ( x `%s %s') (weight set to %d)",
+ INF0206 => "Delete server from l7vsd: `%s %s' ( x `%s %s')",
# server change
INF0301 => "Added real server. (`%s')",
INF0302 => "Added fallback server. (`%s')",
after the configuration file changed on disk. However, if B<autoreload>
is set to B<yes>, the configuration is reloaded anyway.
-=item B<fallback = >I<ip_address|hostname[:portnumber|servicename]> [B<masq>]
+=item B<fallback = >I<ip_address|hostname[:portnumber|servicename]> [B<masq>|B<tproxy>]
the server onto which a web service is redirected if all real
servers are down. Typically this would be 127.0.0.1 with
This directive may also appear within a virtual server, in which
case it will override the global fallback server, if set.
-Only a value of B<masq> can be specified here. The default is I<masq>.
+Also you can set either B<masq> or B<tproxy> as fallback forwarding
+mechanism. The default is B<masq>.
=item B<logfile = ">I</path/to/logfile>B<">|syslog_facility
=over
-=item B<real => I<ip_address|hostname[-E<gt>ip_address|hostname][:portnumber|servicename>] [B<masq>] [I<n>] [B<">I<request>B<", ">I<receive>B<">]
+=item B<real => I<ip_address|hostname[-E<gt>ip_address|hostname][:portnumber|servicename>] [B<masq>|B<tproxy>] [I<n>] [B<">I<request>B<", ">I<receive>B<">]
Defines a real service by IP-address (or hostname) and port (or
servicename). If the port is omitted then a 0 will be used.
Optionally a range of IP addresses (or two hostnames) may be
given, in which case each IP address in the range will be treated as a real
server using the given port. The second argument defines the forwarding
-method, it must be B<masq> only. The third argument defines the weight of
+mechanism, it must be B<masq> or B<tproxy>. The third argument defines the weight of
each real service. This argument is optional. Default is 1. The last two
arguments are optional too. They define a request-receive pair to be used to
check if a server is alive. They override the request-receive pair in the
string starts with I<http://...> the IP-address and port of the real server
is overridden, otherwise the IP-address and port of the real server is used.
-=item B<module => I<proto-module module-args [opt-module-args]>
+=item B<module => I<proto-module [opt-module-args]>
Indicates the module parameter of B<l7directord>. Here B<proto-module>
-denotes the protocol module name (For example, pfilter). B<module-args> denotes the
-arguments for the protocol module (For example, --pattern-match '*.html*').
-B<module-args> is optional only when set B<sessionless>, B<ip> and B<sslid> module to B<proto-module>.
-The last argument is optional (For example, --reschedule).
+denotes the protocol module name (For example, sessionless).
+The last argument B<opt-module-args> is optional (For example, --reschedule).
=back
until the number of bandwidth become below the qosdown limit.
B<K>(kilo), B<M>(mega) and B<G>(giga) unit are available.
-=item B<sorryserver =>I<ip_address|hostname[:portnumber|servicename]>
+=item B<sorryserver =>I<ip_address|hostname[:portnumber|servicename]> [B<masq>|B<tproxy>]
Defines a sorry server by IP-address (or hostname) and port (or
-servicename). Firewall-mark settings cannot be set.
-If the number of requests to the virtual service cross the maxconn limit, the requests would be
-redirected to the sorry server.
+servicename). The second argument defines the forwarding mechanism, it must be B<masq> or B<tproxy>.
+Firewall-mark settings cannot be set.
+If the number of requests to the virtual service cross the maxconn limit, or no available
+real server exists, then the requests would be redirected to the sorry server.
=item B<checktype = negotiate>|B<connect>|I<N>|B<ping>|B<custom>|B<off>|B<on>
designated.
-=item B<socketoption = ">I<OPTION,OPTION, ...>B<">
+=item B<socketoption = ">I<OPTION...>B<">
-An option of the socket used in VirtualService (TCP) is designated.
+An option of the socket used in VirtualService is designated.
The setting possible value is described.
-1.deferaccept
- In a listener socket of VirtualService, TCP_DEFER_ACCEPT setting.
+=over
+
+=item B<transparent>
-2.nodelay
- In a socket for communication with Client in Session and RealServer, TCP_NODELAY setting.
+Set IP_TRANSPARENT option to the RealServer socket.
-3.cork
- In a socket for communication with Client in Session and RealServer, TCP_CORK setting.
+=item B<deferaccept>
-4.quickackon or quickackoff
- In a socket for communication with Client in Session and RealServer, TCP_QUICKACK setting.
+Set TCP_DEFER_ACCEPT option to the listener socket of VirtualService.
-example:
- socketoption=deferaccept,nodelay,quickackoff
+=item B<nodelay>
-=item B<accesslog = ">I<ACCESSLOG_ROTATE_TYPE>B<">
+Set TCP_NODELAY option to the Client and RealServer socket.
-A presence of access log output is established.
-yes: outputs/no: doesn't output.
+=item B<cork>
-=item B<accesslog_rotate_type = date>|B<size>|B<datesize>
+Set TCP_CORK option to the Client and RealServer socket.
-The rotation type designates "date" "size" "datesize".
+=item B<quickackon> or B<quickackoff>
+
+Set or unset TCP_QUICKACK option to the Client and RealServer socket.
+
+=back
+
+=item B<accesslog = >[B<yes>|B<no>]
+
+If B<yes>, then output client access log. The default is B<no>.
+
+=item B<accesslog_rotate_type = >[B<date>|B<size>|B<datesize>]
+
+B<date> means rotate access log with the specified date/time. B<size> means rotate access log when that file size exceeds the specified size. B<datesize> means both B<date> and B<size>.
=item B<accesslog_rotate_max_backup_index = >I<n>
-The maximum number of back-up file is designated.
+Maximum number of backup files.
=item B<accesslog_rotate_max_filesize = > I<n>[B<K>|B<M>|B<G>]
-The most large size of log is designated.
-When "size" and "datesize" are set as accesslog_rotate_type, it becomes indispensable. K(kilo), M(mega) and G(giga) unit are available.
+Threshold file size of access log when B<accesslog_rotate_type> is set to B<size> or B<datesize>. B<K>(kilo), B<M>(mega) and B<G>(giga) units are available.
-=item B<accesslog_rotate_rotation_timing = year>|B<month>|B<week>|B<date>|B<hour>
+=item B<accesslog_rotate_rotation_timing = >[B<year>|B<month>|B<week>|B<date>|B<hour>]
-It's designated at the timing of a rotation.
-When "date" and "datesize" are set as accesslog_rotate_type, it becomes indispensable.
+Rotate timing type when B<accesslog_rotate_type> is set to B<date> or B<datesize>.
=item B<accesslog_rotate_rotation_timing_value = ">I<rotation_timing_value>B<">
-When "year" was designated as accesslog_rotate_rotation_timing.
- FORMAT: "MM/dd hh:mm" MM(month) dd(day) hh(hour):mm(minute)
+Rotate timing. The formats are different by B<accesslog_rotate_rotation_timing> setting.
+
+=over
+
+=item B<accesslog_rotate_rotation_timing=year>
-When "month" was designated as accesslog_rotate_rotation_timing.
- FORMAT: "dd hh:mm" dd(day) hh(hour):mm(minute)
+FORMAT: B<"MM/dd HH:mm">
-When "week" was designated as accesslog_rotate_rotation_timing.
- FORMAT: "<week> hh:mm" sun|mon|tue|wed|thu|fri|sat(week) hh(hour):mm(minute)"
+=item B<accesslog_rotate_rotation_timing=month>
+
+FORMAT: B<"dd HH:mm">
+
+=item B<accesslog_rotate_rotation_timing=week>
+
+FORMAT: B<">[B<sun>|B<mon>|B<tue>|B<wed>|B<thu>|B<fri>|B<sat>] B<HH:mm">
+
+=item B<accesslog_rotate_rotation_timing=date>
+
+FORMAT: B<"HH:mm">
+
+=item B<accesslog_rotate_rotation_timing=hour>
+
+FORMAT: B<"mm">
+
+=back
-When "date" was designated as accesslog_rotate_rotation_timing.
- FORMAT: "hh:mm" hh(hour):mm(minute)
+=item B<session_thread_pool_size = >I<n>
-When "hour" was designated as accesslog_rotate_rotation_timing.
- FORMAT: "mm" mm(minute)
+Defines the size each of session_thread_pool_size.
+Default is session_thread_pool_size parameter at l7vs.cf.
=back