Alternative Solution To Sideband Connection

Problem this snippet solves:

Sideband functionality introduced in v. 11.0 gives a great possibility to call an external resource before a load balancing decision has been made. In many cases, the information, required for a load balancing decision, doesn't change too fast, so instead of making synchronous call via Sideband for each incoming connection, it makes sense to collect that information from an external resource periodically, and then use it for incoming connections management. That gives some performance benefits and this solution can be implemented on version 9.x or 10.x.

How to use this snippet:

Implementation

Implementation consists of the following objects:

Pool "DummyPool1" with the monitor SBMonitor, that is configured to send the required query to the external resource, and with the member "DummyVS". Virtual Server "DummyVS", that has the "TableUpdate" iRule attached to it, and "DummyPool2" as a default pool. Pool "DummyPool2" which has an External Resource to be queried set as a pool member.

SBMonitor, attached to the first pool, periodically queries the DummyVS with the required query, which forwards that query to the second pool and the External Resource. Table_Update iRule intercepts the response from the External Resource, parses it and populates the in-memory table.

The main iRule, that contains the business logic, simply queries the table, populated by the Table_Update iRule, and makes the load balancing decision accordingly.

Sample Code

The TableUpdate iRule, which intercepts the response to the monitor's query from the external IIS server, parses it to find a pattern "Domain\Username:ModuleAndEventText>" and populates the Sessionslist sub-table with the username and the name of the site where the user's session was found:

when RULE_INIT {
log local0. "rule init"
set static::StatusSubtableName "Sessions_list"
set static::sql_debug 1
set static::Site1Name "LA"
set static::SQL_response ""
set static::domain_Netbios "BDD"
set static::IIS_Timeout_Entry 60
}

when HTTP_REQUEST {
set log_prefix "[IP::remote_addr]:[TCP::remote_port clientside] [IP::local_addr]:[TCP::local_port clientside]"
if {$static::sql_debug > 1} { log local0. ": HTTP Request: [HTTP::uri]"}
}

when HTTP_RESPONSE {
if {$static::sql_debug > 1} { log local0. ": HTTP response: [HTTP::status]"}
HTTP::collect [HTTP::header Content-Length]
}

when HTTP_RESPONSE_DATA {
if {$static::sql_debug > 1} { log local0. ": HTTP response data: [HTTP::payload]"}

if {[HTTP::payload] contains $static::SQL_response } {
if { not ( [findstr [HTTP::payload]  "ModuleAndEventText>"] eq "" ) } {

set user_array [split [HTTP::payload] "\n"]

foreach line $user_array {
if {$static::sql_debug > 1} { log local0. ": line: $line"}
set user_string [findstr $line $static::domain_Netbios\\ 0 ":ModuleAndEventText>"]
if {$static::sql_debug > 1} { log local0. ": user_string: $user_string"}
if { not ($user_string eq "") } {
set user_string [string tolower [findstr $user_string $static::domain_Netbios 0 " "]]
if {$static::sql_debug > 0} { log local0. ": Adding to the table: $user_string $static::Site1Name" }
table set -subtable $static::StatusSubtableName $user_string $static::Site1Name $static::IIS_Timeout_Entry
}
}
}
HTTP::respond 200 "OK"
} else {
log local0. ": Didn't get response from IIS Server"
HTTP::respond 500 "ERROR"
}
}

The main iRule, that gets the username information from the client's request and sends the new connection either to the Pool Name from the Sessionslist table, or to the CommonPool:

#NO ONECONNECT !!!!
when RULE_INIT {
log local0. "rule init"
set static::domain_Netbios "BDD"
set static::StatusSubtableName "Sessions_list"
set static::Default_Pool "Common_Pool"
$static::sb_debug 1
}

when CLIENTSSL_HANDSHAKE {
log local0. "Client SSL handshake"
  setPool_Name ""
set log_prefix "[IP::remote_addr]:[TCP::remote_port clientside] [IP::local_addr]:[TCP::local_port clientside]"
    if {$static::sb_debug > 1} { log local0. "Client SSL Handshake: $log_prefix"}
SSL::collect
}

when CLIENTSSL_DATA {
if {$static::sb_debug > 1} { log local0. ": Client SSL Data-------------------"}
if {$static::sb_debug > 1} { log local0. ": SSL Payload: [SSL::payload]"}
set username [findstr [SSL::payload] "username" 30 ""]
set username [string tolower $username]
set Pool_Name [table lookup -subtable $static::StatusSubtableName [string tolower $static::domain_Netbios\\$username] ]
if {$static::sb_debug > 1} { log local0. ": site_id: $Pool_Name"}
if { not ($Pool_Name  eq "") } {
if {$static::sb_debug > 0} { log local0. ": Existing session found, Pool Name is $Pool_Name "}
LB::detach
pool $Pool_Name
} else {
if {$static::sb_debug > 0} { log local0. ": This is the new session"}
LB::detach
pool $static::Default_Pool
}
SSL::release
}

Code :

when RULE_INIT {
log local0. "rule init"
set static::StatusSubtableName "Sessions_list"
set static::sql_debug 1
set static::Site1Name "LA"
set static::SQL_response ""
set static::domain_Netbios "BDD"
set static::IIS_Timeout_Entry 60
}

when HTTP_REQUEST {
set log_prefix "[IP::remote_addr]:[TCP::remote_port clientside] [IP::local_addr]:[TCP::local_port clientside]"
if {$static::sql_debug > 1} { log local0. "<$log_prefix>: HTTP Request: [HTTP::uri]"}
}

when HTTP_RESPONSE {
if {$static::sql_debug > 1} { log local0. "<$log_prefix>: HTTP response: [HTTP::status]"}
HTTP::collect [HTTP::header Content-Length]
}

when HTTP_RESPONSE_DATA {
if {$static::sql_debug > 1} { log local0. "<$log_prefix>: HTTP response data: [HTTP::payload]"}

if {[HTTP::payload] contains $static::SQL_response } {
if { not ( [findstr [HTTP::payload]  "ModuleAndEventText>"] eq "" ) } {

set user_array [split [HTTP::payload] "\n"]

foreach line $user_array {
if {$static::sql_debug > 1} { log local0. "<$log_prefix>: line: $line"}
set user_string [findstr $line $static::domain_Netbios\\ 0 ":ModuleAndEventText>"]
if {$static::sql_debug > 1} { log local0. "<$log_prefix>: user_string: $user_string"}
if { not ($user_string eq "") } {
set user_string [string tolower [findstr $user_string $static::domain_Netbios 0 " "]]
if {$static::sql_debug > 0} { log local0. "<$log_prefix>: Adding to the table: $user_string $static::Site1Name" }
table set -subtable $static::StatusSubtableName $user_string $static::Site1Name $static::IIS_Timeout_Entry
}
}
}
HTTP::respond 200 "OK"
} else {
log local0. "<$log_prefix>: Didn't get response from IIS Server"
HTTP::respond 500 "ERROR"
}
}
Published Mar 12, 2015
Version 1.0