Forum Discussion

Chris_13067's avatar
Chris_13067
Icon for Nimbostratus rankNimbostratus
Oct 29, 2008

persistence based on text in payload

Hi,

 

 

I have an app that initiates a TCP connection to a server, which performs a login function, and returns a text string to be used as a session ID. The initial connection is then closed. I need subsequent reqests referencing the session ID to persist to the same server. The session ID always appears at a certain offset and is 32 bytes long.

 

 

I don't have much experience with iRules and haven't gotten this working so far. Any help to point me in the right direction, or similar examples would be greatly appreciated.

 

 

Thanks

 

8 Replies

  • I think the concept is same as jsessionid persistent.

     

    detect information from server response and add it to persistent table.

     

     

    http://devcentral.f5.com/wiki/default.aspx/iRules/Weblogic_JSessionID_Persistence.html

     

     

    however, jsessionid case would be easier since it is http protocol and information is in cookie.

     

     

    in your case, if it is generic tcp, you may have to use irule based on TCP event, etc.

     

     

    something like this

     

     

    on the initial connection:

     

     

    when SERVER_ACCEPTED {

     

    TCP::collect

     

    }

     

    when SERVER_DATA {

     

    let say it is at byte 20

     

    persist add uie [string range [TCP::payload] 20 51]

     

    }

     

     

    and for the subsequent requests

     

    when CLIENT_ACCECPTED {

     

    TCP::collect

     

    }

     

    when CLIENT_DATA {

     

    let say session id is at byte 100

     

    persist uie [string range [TCP::payload] 100 131]

     

    }

     

     

    if you can share packet trace of your application, that would help
  • Thanks,

     

     

    Here's what I have so far:

     

     

    when CLIENT_ACCEPTED {

     

    log local0. "Buildup -- collecting client data"

     

    TCP::collect 60 0

     

    set server_hold 0

     

    }

     

    when SERVER_CONNECTED {

     

    log local0. "Buildup -- collecting server data"

     

    TCP::collect 60 0

     

    set server_hold 1

     

    }

     

    when CLIENT_DATA {

     

    set CliSessionId [string range [TCP::payload] 22 53]

     

    log local0. "Clisession ID is $CliSessionId"

     

    if {[string is alnum $CliSessionId] == 1} {

     

    log local0. "This is an existing connection"

     

    persist uie $CliSessionId

     

    event disable all

     

    }

     

    elseif {$server_hold == 1} {

     

    log local0. "This is a new Session - passthrough"

     

    }

     

    TCP::release

     

    }

     

    when SERVER_DATA {

     

    set SvrSessionId [string range [TCP::payload] 22 53]

     

    log local0. "Svrsession ID is $SvrSessionId"

     

    persist add uie $SvrSessionId

     

    TCP::release

     

    event disable all

     

    }

     

     

    I can see in the log that it's working as I would expect except new TCP sessions referencing the session id are just load balanced between multiple servers - they do not persist to the previous server.

     

     

    I'm sure this is something basic that I've missed, maybe how I applied the iRule? Or am I not using the persist command correctly?

     

     

    I tried applying the iRule directly to the virtual server with persistence set to 'None', and I tried to create a new persistence profile referencing the iRule (based on universal), but it still doesn't work.

     

     

    Any help would be appreciated.

     

    Thanks.

     

  • You shouldn't need to use a persistence profile if you're specifying UIE persistence in the iRule. It would be good to add a timeout on the persist add statement though.

     

     

    So when a client makes a subsequent request with a valid string, you see the correct persistence string logged, but the request is load balanced? If you run 'b persist mode universal show all' on the command line, do you see the correct pool member associated with the persistence string?

     

     

    Are there multiple requests being sent on the same TCP connection? Why have you disabled the any future events on the TCP connection with 'event disable all'?

     

     

    Aaron
  • you may also verify with "persist lookup" in irule and/or CLI command line "b persist show all"

     

    btw, client and server hit the same virtual server, right?
  • Thanks,

     

     

    I added a timeout value and have the iRule applied directly to the virtual server rather than using a profile.

     

     

    It looks like the sessions are persisting correctly from the cli, but I see connections being sent to both servers in the pool through the gui. The connection count is incrementing at the same rate. App issue maybe, I'm going to get at trace on the second server (where connections should not be sent).

     

     

    For the 'event disable all', I thought that would exit any furthur iRule evaluation once the persistence string is found. Let me know if I misunderstood how it is used.

     

     

    Would I use the 'persist lookup' within the iRule to verify an entry extists for the session ID string?

     

     

    I don't understand what you mean by 'client and server hit the same virtual server'.

     

     

    Also, I used the line 'if {[string is alnum $CliSessionId] == 1}' because I couldn't figure out how to match a null string which shows up in the log as 'ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ', if there are suggestions on matching that string please let me know.

     

     

    Thanks for your help and patience, and please keep in mind I have very little experience with writing iRules, so if I've made any dumb mistakes, that's why.

     

     

    I made a couple changes to the current rule, here's the latest:

     

     

    when CLIENT_ACCEPTED {

     

    log local0. "Buildup -- collecting client data"

     

    TCP::collect 60 0

     

    log local0. "Client data collected"

     

    }

     

    when SERVER_CONNECTED {

     

    log local0. "Buildup -- collecting server data"

     

    TCP::collect 60 0

     

    log local0. "Server data collected"

     

    }

     

    when CLIENT_DATA {

     

    set CliSessionId [string range [TCP::payload] 22 53]

     

    log local0. "Clisession ID is $CliSessionId"

     

    if {[string is alnum $CliSessionId] == 1} {

     

    log local0. "This is an existing connection"

     

    persist uie $CliSessionId

     

    event disable all

     

    }

     

    else {

     

    log local0. "This is a new Session - passthrough"

     

    }

     

    TCP::release

     

    }

     

    when SERVER_DATA {

     

    set SvrSessionId [string range [TCP::payload] 22 53]

     

    log local0. "Svrsession ID is $SvrSessionId"

     

    if {[string is alnum $SvrSessionId] == 1} {

     

    log local0. "Setting Svr Session persistence"

     

    persist add uie $SvrSessionId 300

     

    }

     

    else {

     

    log local0. "Svr Session ID not alnum"

     

    }

     

    TCP::release

     

    event disable all

     

    }

     

     

  • sorry I wrote it too fast.

     

    what I mean is.. how many virtual server do you have (which using this irule)?

     

    if you have only one virtual, that is fine.

     

    in some case, somebody may have persist record added on one virtual and use it in another virtual. this one you may need "any" keyword.

     

     

    for data string/session id which is not text string, it might be easier if you use "binary scan command" here is an example

     

     

    @22 (at byte 22) read as H64 (hex - 1 byte = H2) save it in variable SvrSessionId

     

    binary scan [TCP::payload] @22H64 SvrSessionId

     

    it is easy to verify hex string with packet trace, but it will consume more memory.

     

  • There is just one virtual server using the irule.

     

     

    So binary scan will be more efficient? How would I compare the data after it's collected to verify non-null info?

     

     

    Thanks.
  • i think binary scan may take a little bit more cpu. but it may give you ability to debug (or you can use string to get data to variable, then use binary scan to convert it to hex. so you can log it to verify with packet trace. after irule is verified, you can remove the debugging part)

     

     

    btw, if you change to use binary scan, here is how to check:

     

    assume null is 0x00 (in hex)

     

    if 32-byte sessionid is null, maybe you can try something like this

     

     

    if { $CliSessionId eq "0x0000000000000000000000000000000000000000000000000000000000000000" }