SUPL ILP Message Based Load Balancing with Persistence
Problem this snippet solves:
This rule provides TCP message-based load-balancing for Secure User Plane Location (SUPL) Internal Location Protocol messages. It uses the Session-ID2.SLC_Session_ID as a key for persistence, and assumes that, for all messages, the SLC_Session_ID.SLC_Session part is an IPv4 address.
Code :
######## # # $VERSION = '1.3' # # ILP Message load-balancing. ILP Messages (part of the SUPL suite) # are described in a PDF document which can be downloaded here: # http://goo.gl/AR2NIZ # Each message begins as follows: # - [2 bytes] Message length in octets # - [3 bytes] ILP Message version (must be 0x02,0x00,0x00) # - [variable] Session ID2 # # The Session ID2 has one, two or three sub-parts, including: # - SLC Session ID # - SET Session ID # - SPC Session ID # # The SLC Session ID is mandatory. SET Session ID is optional. The # SPC Session ID is mandatory except for messages of type PREQ. This # iRule uses the SLC Session ID only as a persistence key. The SLC # Session ID is: # - [4 bytes] Session ID # - [variable] SLC ID # The SLC ID sub-part is either an IPv4 address, an IPv6 address or a # variable length FQDN. This iRule assumes the SLC ID is a four-byte # IPv4 address, but the iRule can be easily extended to support all three # types. # # ILP is encoded using canonical PER rules, so the actual bitwise encoding is: # # 16 bits- message length # 24 bits- version # 1 bit- is setSessionID present # 1 bit- is spcSessionID present # 32 bits- slcSessionID.sessionID # 1 bit- is slcSessionID.slcID IP(0) or FQDN(1) # [ if slcSessionID.slcID is IP: ] # 1 bit- is slcSessionID.slcID IPv4(0) or IPv6(1) # [ if slcSessionID.slcID is ipv4: ] # 32 bits- slcSessionID.ipv4Addr # # Since this code assumes slcSessionID.slcID is IPv4, the bit selectors # are passed over without inspection # # Over a single TCP connection, multiple ILP messages may arrive, and # the messages may have differing Session ID2 values (including differing # SLC Session IDs). This iRule uses TCP message-based load-balancing # (mblb) to direct messages to multiple back-end servers (presumably # SPCs). It ensures that messages with the same SLC Session ID are # directed to the same SPC. It utilizes the persistence table, so if # persistence mirroring is enabled, the table entries will be copied # to a standby LTM and will survive a failover. Messages may span # multiple TCP segments, and a single TCP segment may contain the # end of one message and the start of another. # # To make this work properly, the mblb profile must be activated on the # Virtual Server to which this iRule is attached. This must be done # using tmsh, as follows (in this example, vs-ilp is the name of the # Virtual Server to which SLCs are sending the ILP messages): # tmsh modify ltm virtual vs-ilp add profiles { mblb { } } # # Because of the message delivery mechanism (TCP::notify eom), this code # only works on 11.5.0 and beyond. # # Potentially useful debugging log statements are commented out. On an # 11.5.0 VE, this rule averages ~350K cycles for CLIENT_DATA, which # is where most of the work happens. # # For TCP mblb here is a breakdown of what's happening: # 1. when a new TCP connection completes (SYN/SYN-ACK/ACK on the LTM # client-side), some variables for the connection are set. The # iRule is instructed to collect TCP data into the payload buffer, # then raise CLIENT_DATA when the buffer is ready for processing; # 2. when CLIENT_DATA is raised, the assumption is that the TCP::payload # buffer is at the start of an ILP message. The first time this event # is raised, that is naturally true. Subsequently, this is guaranteed # because TCP::release is not called until the payload buffer contains # at least one full message. When TCP::release is called, it only # releases one message-worth of data at a time; # 3. initially in CLIENT_DATA, the code verifies that there are at least 14 # bytes of data in the payload buffer. This ensures that there is enough # data to extract the message length and the slcSessionID. If there is # not yet 14 bytes, it continues to collect until there is. Once the message # is extracted, the message persistence entry is added to the persistence table. # Once the entire message length is collected, the message is delivered, # which happens when 'TCP::notify eom' is invoked; # 4. On the serverside, 'TCP::notify eom' is executed when an entire message is # found. The normal BIG-IP mechanism is to send the response back to the # matching client-side TCP socket, which is the desired outcome here, so nothing # special needs to occur. # # (2013-Nov-27) Initial Version; Vernon Wells, F5 Networks # (2014-Jan-17) Version 1.1; Properly accounts for bit selectors in slcSessionID # (2014-Feb-05) Version 1.2; Use 'TCP::notify eom' rather than 'TCP::notify request' # and use a while loop to more sensibly extract multiple # messages from the TCP::payload buffer # (2014-Feb-08) Version 1.3; Notify of messages from server side # # supl_ilp_mblb Copyright (c) 2013, F5 Networks, Inc. All rights reserved. # ##### when RULE_INIT { #set static::im_run 03 } when CLIENT_ACCEPTED { TCP::collect } when CLIENT_DATA { #log local0. "{$static::im_run} Entering CLIENT_DATA. payload length = [TCP::payload length]" while { [TCP::payload length] > 14 } { #log local0. "{$static::im_run} ... more than 14 bytes remain in stream" binary scan [TCP::payload] "S1c3Wc" message_length ilp_version ssa ssb set message_length [expr { $message_length & 0xffff }] #log local0. "{$static::im_run} ... ... extracted message_length = $message_length" if { [TCP::payload length] < $message_length } { #log local0. "{$static::im_run} ... ... more data must be collected to reach message_length" TCP::collect return } set sessionID [expr { (($ssa << 2) >> 32) & 0xffffffff }] set ssc [expr { (($ssa << 8) | $ssb) << 26 }] set slcIP [expr { (($ssc << 3) >> 32) & 0xffffffff }] set slcSessionID "$sessionID:$slcIP" #log local0. "{$static::im_run} ... ... slc_session = $slcSessionID ($sessionID, $slcIP)" persist uie $slcSessionID TCP::release $message_length TCP::notify eom } TCP::collect } when SERVER_CONNECTED { TCP::collect } when SERVER_DATA { while { [TCP::payload lengt] > 2 } { binary scan [TCP::payload] "S1" message_length set message_length [expr { $message_length & 0xffff }] #log local0. "{$static::im_run} Server side, message_length = $message_length" if { [TCP::payload length] < $message_length } { #log local0. "{$static::im_run} ... Server side, more data must be collected to reach message_length" TCP::collect return } else { #log local0. "{$static::im_run} ... Server side, message delivered" TCP::release $message_length TCP::notify eom } } #log local0. "{$static::im_run} ... Server side, completing iteration of SERVER_DATA" TCP::collect }
Published Mar 18, 2015
Version 1.0VernonWells
Employee
Joined August 23, 2012
VernonWells
Employee
Joined August 23, 2012
No CommentsBe the first to comment