Forum Discussion

karmacoma_49245's avatar
karmacoma_49245
Icon for Nimbostratus rankNimbostratus
Jul 10, 2008

iRule disconnects the client when switch from one server to another

Hi guys

We are newbies when writing iRules and I'm afraid we need some help. Our iRule is supposed to assign a different LDAP server depending on a subscriber id.

Let's say we have two OpenLDAP DBs and we have to route the traffic to one or the other. If we receive a search for DB1 the iRule routes it properly and the transaction is finished.

If then we receive a new message for DB2 the iRule sends it to the DB2. Note we have set the OpenLDAP so there is no need for a bind to be sent before a search for example is sent.

The problem we are having is that when a new search for DB2 is coming into the F5 while the F5 has still not closed the previous LDAP dialogue towards the DB1, we get a TCP reset towards both sides of the F5 leading into disconnection of the client and affecting performance.

We think we may need to buffer the messages until the previous dialogue is finished so that no message is lost and no reset is sent however we don't know hot to do so, any ideas???

Another possible solution could be to reject the incoming messages while a previous message is processed but we have try with no success.

Here is our iRule

   
  rule ldapProxy {  
     when RULE_INIT {  
   Define default ldap server and port  
      set ::ldapPool Internal_Pool  
      set ::ldapPort 389  
   Turn on debugging  
      set ::debug 1  
   Define a lookup table for debugging  
      array set ::msg_types {  
             0 "bind request"  
             1 "bind response"  
             2 "unbind request"  
             3 "search request"  
             4 "search response"  
             6 "modify request"  
             7 "modify response"  
             8 "add request"  
             9 "add response"  
            10 "delete request"  
            11 "delete response"  
            12 "modifydn request"  
            13 "modifydn response"  
            14 "compare request"  
            15 "compare response"  
            16 "abandon request"  
            23 "extended request"  
            24 "extended response"  
      }  
  }  
    
  when CLIENT_ACCEPTED {  
      TCP::collect  
  }  
    
  when CLIENT_DATA {  
   Grab the current payload collected  
      set payload [TCP::payload]  
      set SUBSID [findstr $payload "MSISDN=" 7 6 ]  
      if {$SUBSID>=491700 and $SUBSID < 491706 } {  
         set NODE "172.80.121.30"  
      } elseif {$SUBSID>= 491723 and $SUBSID < 491724 } {  
         set NODE "172.80.121.31"  
      } else  {  
      }  
    
   Pull the first 2 bytes.  
      binary scan $payload H2c ber_t ber_len  
    
   The first byte is the tag signifying an LDAP message,  
   Always is hex 30, if that is not so reject  
      if { $ber_t ne "30" } {  
          reject  
          return  
      }  
    
   The second byte is one of two values:  
         a) The length of the packet minus the above  
            defining byte and the length byte  
      OR  
         b) an octet describing how many subsequent bytes  
            hold the packet length  
   In either case the message type (what we are after)  
   follows the message id field which too can be a variable  
   number of bytes.  
    
      set len_bytes 0  
      if { [expr [expr ($ber_len + 0x100) % 0x100] & 128] > 0 } {  
          set len_bytes [expr [expr ($ber_len + 0x100) % 0x100] & 127]  
      }  
    
   How many bytes is the message id  
      binary scan $payload x[expr 3 + $len_bytes]c msgid_bytes  
    
   The message type is then 4 bytes + number length bytes + number of  
   message id bytes offset.  
      binary scan $payload x[expr 4 + $len_bytes + $msgid_bytes]c msgtype  
    
    
   msgtype - BER encoded value, bits 1-5 are the actual  
   type, 6 is the data type, 7-8 are the data class  
   Here we only care about the lower 5 bits  
    
      set msgtype [expr $msgtype & 31]  
      if {$::debug and  
          [catch {  
                log local0. "message type is: $::msg_types($msgtype) $msgtype"  
           }  
          ]  
         } {  
         log local0. "Bad message type: $msgtype"  
         reject  
      }  
    
   Each connection should start with a bind request  
    
      if { $msgtype == 0 } {  
         if {$::debug} {log local0. "Bind Request with: $::ldapPool"}  
         pool $::ldapPool  
      } elseif {[string compare [LB::server addr] $NODE] -- 0}{  
         if {$::debug} {log local0. "Sending  to node : $NODE"}  
         LB::detach         
         node $NODE $::ldapPort  
      }  
      TCP::release  
      TCP::collect  
  }  
  }  
 

thanks a lot in advance!

7 Replies

  • Hi nmenant

     

     

    thanks a lot for such a fast reply!

     

     

    we are continuously checking the ltm with tail -f but we don't get any TCL error. We just know there has been a reset when the client sends a new bind towards the servers (through the F5, of course) but nothing else.

     

     

    Regards O.
  • Hi,

     

     

    i just read the iRule and since i'm not a master in LDAP protocol it seems nice except maybe the LB::detach in CLIENT_DATA. Never tried this one but since you seem to do this when you want to move on the other LDAP server that may be the problem.

     

     

    May it be possible for you to do the following:

     

    Add some troubleshooting log commands always everywhere in your iRule so that we can follow step by step what is happening in your iRule.

     

     

    Then do your test and please print us your output of /var/log/ltm.

     

     

    It may help newbie like me to help you !

     

     

    Regards

     

     

    N.
  • Hi nmenant

     

     

    it seems that is not the problem, see what happens when we remove the detach

     

     

    Jul 10 12:04:30 tmm tmm[1664]: Rule ldapproxy_system3_detach_test : message type is: search request 3

     

    Jul 10 12:04:30 tmm tmm[1664]: Rule ldapproxy_system3_detach_test : message type is: search request 3

     

     

    Jul 10 12:04:55 tmm tmm[1664]: Rule ldapproxy_system3_detach_test : message type is: search request 3

     

    Jul 10 12:04:55 tmm tmm[1664]: Rule ldapproxy_system3_detach_test : Sending to node : 172.80.121.31

     

    Jul 10 12:04:55 tmm tmm[1664]: 01220001:3: TCL error: ldapproxy_system3_detach_test - Address in use (line 1) invoked from within "node $NODE $::ldapPort"

     

     

    it looks like we are trying to set up a connection towards a node using an address which already exists....

     

     

    thanks

     

    k.
  • Hi,

     

     

     

    it seems to be a known issue when using pool or node command for udp traffic within CLIENT_ACCEPTED event. For what the support says, it shouldn't interrupt UDP traffic but maybe you should open a support case.

     

     

    F5 reference number to this issue is CR69801.

     

     

    HTH

     

     

    N.
  • Hi nmenant!

     

     

    Maybe I'm much more newbie than I thought. I have tried to look for the C69801 case but couldn't find it either in the Cases or in the F5 Knowledge Base. Could you please let me know where I can find it ?

     

     

    On the other hand we are not using UDP, just TCP so it may not apply.

     

     

    Thanks

     

    Oscar
  • Hi nmenant!

    here is a little drawing of what it is happening at TCP level. This is the sequence when it is successful:

     
      Ldap ClientVIPF5Server1Server2  
      =============================  
        
             LDap Search  
      ----------------->  
                                  TCP(SYN)  
                              ----------->  
       TCP(ACK)  
       <---------------                       TCP(FIN/ACK)  
                              --------------------------->  
                                
                               TCP(SYN/ACK)  
                              <-----------  
                                   TCP(ACK)                          
                              ------------>   
                               Ldap Search  
                              ------------>  
                                
                              TCP(FIN(ACK)  
                              <---------------------------  
                                
                                                   TCP(ACK)  
                              ----------------------------->  
                                
                              TCP(ACK)  
                              <----------------------------      
                                
                              :::::::::::::::::::::::::::  
                              ::::::::::::::::::::::::::::  
      

    On the other hand this is the sequence when it fails:

     
      Ldap ClientVIPF5Server1Server2  
      =============================  
        
             LDap Search  
      ----------------->  
                                                    TCP(SYN)  
                              ----------------------------->  
       TCP(ACK)  
       <---------------       TCP(FIN/ACK)  
                              --------->     
            
             LDap Search  
      ----------------->       ******   
                                
       TCP(ACK)  
      <---------------       
        
       TCP(RST/ACK)  
      <---------------                           
                                TCP(SYN/ACK)  
                               <---------------------------  
                                 
                                                  TCP(RST)  
                               -------------------------->  
                                 
                               TCP(FIN/ACK)  
                               <------------  
                                
                                  TCP(ACK)  
                               ------------->            
      
     

    as you can see there is an incoming search for the second server ongoning when a search for the first one comes in. The F5 hasn't finished the reconnection and sends resets to both sides (client and server).

    This is what we want to avoid (in particular the RST to the client). We have already tried to modify the tcp profile settings but no success. We are thinking about two iRules, one for server one and another one for server two.

    We are not sure about how to handle this but we will try. The other possibility would be to try buffering but looks more complicated and we don't even know how to start.

    Any other alternatives or ideas on how to implement this?

    Thanks a lot in any case!