How to generate the persistence cookie with an iRule

Problem this snippet solves:

When you configure a cookie persistence profile to use the HTTP Cookie Insert or HTTP Cookie Rewrite method, the BIG-IP system inserts a cookie into the HTTP response. The cookie value contains the encoded IP address and port of the destination server. Exemple of a cookie value : 1677787402.36895.0000

(See SOL6917 for more information about this topic)

Let's assume that you want your pool member to receive a copy of this cookie value in an HTTP header. Because for example you want your application to forge an url where the cookie value is in a GET parameter. (NOTE : I cannot modify the behavior of the application, I can only play with headers)

Retrieving the cookie value is pretty easy with iRule : [HTTP::cookie value $cookie_name]

But you'll notice that there is a little issue with this feature: when you are a new visitor, the persistence cookie is inserted in the HTTP response ... Meaning that for the very first hit made by the visitor, there will be NO cookie value to retrieve ...

In my scenario it was an issue to miss this cookie value on the first hit, so I had to come up with a solution to forge the cookie value based on pool member IP and port when the persistence cookie is missing.

I chose to adapt the code found here and there (thanks !)

EDIT : Well I figured out that if you are not using a default route-domain the persistence cookie value will be different (see https://support.f5.com/csp/article/K6917 )

Here is the alternative code bloc to use IPv4 non-default route domains:

set ADDR "[format %02x $a][format %02x $b][format %02x $c][format %02x $d]"
set PORT [LB::server port]
set COOKIE "rd2o00000000000000000000ffff${ADDR}o${PORT}"

How to use this snippet:

To summarize what the iRule does : if the persistence cookie doesn't exist (most likely because it's the very first hit), then calculate it from member IP and PORT (it obviously has to be after the "When LB_SELECTED" statement) ; else just read the existing cookie.

You can set the $cookie_name parameter manually, or let the iRule identify it

Code :

when LB_SELECTED {
    
#set cookie_name SERVERID
# following function could determine persistence cookie name being used if not manually set by the previous line
    if {not [info exists cookie_name]} {
if { [set cookie_name [PROFILE::persist mode cookie cookie_name]] eq "" } { set cookie_name "BIGipServer[getfield [LB::server pool] "/" 3]" }
                #Default cookie name requires the getfield "/" 3 purge otherwise it's /Common/pool_name
    }
if { [set COOKIE [HTTP::cookie value $cookie_name]] == "" } {
scan [LB::server addr] {%d.%d.%d.%d} a b c d
set ADDR [expr { $a + $b * 256 + $c * 65536 + $d * 16777216 }]
set PORT [ntohs [LB::server port]]
set COOKIE "${ADDR}.${PORT}.0000"
## Following bloc must be used instead if you are using non-default route domains, see K6917
#set ADDR "[format %02x $a][format %02x $b][format %02x $c][format %02x $d]"
#set PORT [LB::server port]
#set COOKIE "rd2o00000000000000000000ffff${ADDR}o${PORT}"
#########
unset a b c d ADDR PORT
#log local0. "$cookie_name = $COOKIE created for [HTTP::uri]"
} else {
#log local0. "$cookie_name = $COOKIE already exists for [HTTP::uri]"
}
HTTP::header insert X-F5-persist $COOKIE

}

Tested this on version:

11.5
Updated Jun 06, 2023
Version 2.0

Was this article helpful?