Subject: [AAA-WG]: Transport-10 review (fwd)

From: Bernard Aboba <[email-masked]>
Date: Wed, 25 Dec 2002 14:05:08 -0800 (PST)

Thank you.

It seems to make sense that *any* message in SUSPECT state will cause
failback.

---------- Forwarded message ----------
Date: Thu, 26 Dec 2002 01:00:07 +0200
From: Jari Arkko <[email-masked]>
To: Bernard Aboba <[email-masked]>
Cc: Jari Arkko <[email-masked]>
Subject: Transport-10 review

Ok, here's some preliminary results. The claim I set out to prove was
"The code in transport-10 is equivalent to the state machine in
transport-10".

The answer is no. Well, its almost equivalent modulo some editorial nits
(see attachment) and one real difference. You should fix the editorials,
and we can discuss the real difference: the code assumes that if you get
*any* message in the SUSPECT state you will immediately failback and go
to OKAY. I'm not quite sure what's right here. Perhaps this depends on
the assumptions on what the transport layer is doing. I might be easily
convinced that any message is good enough; if the peer is responding on
either TCP or SCTP then there must be some bidirectional connectivity.
Note that on the application layer you could be just getting DWR which
doesn't prove that the peer app has heard you. But maybe this is enough.

Then there's a few further questions which you might want some answers.
I have marked the answers below in case I have them. Getting the rest
would mean more work.

- Does the state machine make sense?

   It does make sense to me. I went through all of it.
   That doesn't prove anything, of course.

- Can the state machine deadlock?

   Hmm.... partial answer below regarding forgetting
   to set the timer. Otherwise, I don't know.

- Can the state machine livelock?

   I think so, you could be stuck forever in REOPEN
   if the sequence of received/missed DWAs is right. I
   believe this is a feature, however, not a bug.

- Is the value of NumDWA in bounds -1..3?

   Yes. Thank god the assignment is "NumDWA = -1", not "NumDWA--"...

- Do we sometimes forget to set the timer, and be doomed for waiting it forever?

   I don't think so. All "timer expired" events lead to SetWatchdog call
   in all cases. Nice.

Jari

- It doesn't seem possible to get ConnectionDown event in the INITIAL state.
  Nice to have the state machine be complete, but this will never happen...

- In the line "INITIAL       Connection up        SetWatchDog()        OKAY"
  you should change s/WatchDog/Watchdog/

- In the line "              Pending &            SetWatchdog"
  you should change s/Watchdog/Watchdog()/

- In the entry

    "SUSPECT       Receive DWA          Pending = FALSE
                                        SetWatchdog()
                                        Failback()           OKAY"

  you should swap the order of the two last actions.

- In the line "REOPEN        Receive Non DWA      Throwaway()          REOPEN"
  you should change s/Non DWA/non-DWA/

STATE         Event                                   Actions                                                       New State
=====         ------                                  -------                                                       ----------
DOWN          Connection down                         CloseConnection()                                             DOWN
DOWN          Connection up                           NumDWA = 0; SendWatchdog(); SetWatchdog(); Pending = TRUE     REOPEN
DOWN          Receive DWA                             Pending = FALSE; Throwaway()                                  DOWN
DOWN          Receive non-DWA                         Throwaway()                                                   DOWN
DOWN          Timer expires                           AttemptOpen(); SetWatchdog()                                  DOWN
INITIAL       Connection down                         CloseConnection(); SetWatchdog()                              DOWN
INITIAL       Connection up                           SetWatchdog()                                                 OKAY
INITIAL       Receive DWA                             Pending = FALSE; Throwaway()                                  INITIAL
INITIAL       Receive non-DWA                         Throwaway()                                                   INITIAL
INITIAL       Timer expires                           AttemptOpen(); SetWatchdog()                                  INITIAL
OKAY          Connection down                         CloseConnection(); Failover(); SetWatchdog()                  DOWN
OKAY          Receive DWA                             Pending = FALSE; SetWatchdog()                                OKAY
OKAY          Receive non-DWA                         SetWatchdog()                                                 OKAY
OKAY          Timer expires & !Pending                SendWatchdog(); SetWatchdog(); Pending = TRUE                 OKAY
OKAY          Timer expires & Pending                 FailOver(); SetWatchdog()                                     SUSPECT
REOPEN        Connection down                         CloseConnection(); SetWatchdog()                              DOWN
REOPEN        Receive DWA & NumDWA < 2                Pending = FALSE; NumDWA++                                     REOPEN
REOPEN        Receive DWA & NumDWA == 2               Pending = FALSE; NumDWA++; Failback()                         OKAY
REOPEN        Receive non-DWA                         Throwaway()                                                   REOPEN
REOPEN        Timer expires & !Pending                SendWatchdog(); SetWatchdog(); Pending = TRUE                 REOPEN
REOPEN        Timer expires & Pending & NumDWA < 0    CloseConnection(); SetWatchdog()                              DOWN
REOPEN        Timer expires & Pending & NumDWA >= 0   NumDWA = -1; SetWatchdog()                                    REOPEN
SUSPECT       Connection down                         CloseConnection(); SetWatchdog()                              DOWN
SUSPECT       Receive DWA                             Pending = FALSE; Failback(); SetWatchdog()                    OKAY
SUSPECT       Receive non-DWA                         Failback(); SetWatchdog()                                     OKAY
SUSPECT       Timer expires                           CloseConnection(); SetWatchdog()                              DOWN
/*
 OnReceive() is called whenever a message
 is received from the peer. This message MAY
 be a request or an answer, and can include
 DWR and DWA messages. Pending is assumed to
 be a global variable.
*/
OnReceive(pcb, msgType)
{
   if (msgType == DWA) {
        Pending = FALSE;
        }
   switch (pcb->Status){
   case OKAY:
        SetWatchdog();
        break;
   case SUSPECT:
        pcb->Status = OKAY;
        Failback(pcb);
        SetWatchdog();
        break;
   case REOPEN:
        if (msgType == DWA) {
           NumDWA++;
           if (NumDWA == 3) {
              pcb->status = OKAY;
              Failback();
           }
        } else {
           Throwaway(received packet);
        }
        break;
   case INITIAL:
   case DOWN:
        Throwaway(received packet);
        break;
   default:
        Error("Shouldn't be here!");
        break;
   }
}

/*
OnTimerElapsed() is called whenever Tw reaches zero (0).
*/
OnTimerElapsed(pcb)
{
    switch (pcb->status){
       case OKAY:
          if (!Pending) {
             SendWatchdog(pbc);
             SetWatchdog();
             Pending = TRUE;
             break;
          }
          pcb->status = SUSPECT;
          FailOver(pcb);
          SetWatchdog();
          break ;
       case SUSPECT:
          pcb->status = DOWN;
          CloseConnection(pcb);
          SetWatchdog();
          break;
       case INITIAL:
       case DOWN:
          AttemptOpen(pcb);
          SetWatchdog();
          break;
       case REOPEN:
          if (!Pending) {
             SendWatchdog(pbc);
             SetWatchdog();
             Pending = TRUE;
             break;
          }
          if (NumDWA < 0) {
             pcb->status = DOWN;
             CloseConnection(pcb);
          } else {
             NumDWA = -1;
          }
          SetWatchdog();
          break;
       default:
          error("Shouldn't be here!);
          break;
       }
}

/*
OnConnectionUp() is called whenever a connection comes up
*/
OnConnectionUp(pcb)
{
    switch (pcb->status){
       case INITIAL:
          pcb->status = OKAY;
          SetWatchdog();
          break;
       case DOWN:
          pcb->status = REOPEN;
          NumDWA = 0;
          SendWatchdog(pcb);
          SetWatchdog();
          Pending = TRUE;
          break;
       default:
          error("Shouldn't be here!);
          break;
       }
}

/*
OnConnectionDown() is called whenever a connection goes down
*/
OnConnectionDown(pcb)
{
    pcb->status = DOWN;
    CloseConnection();
    switch (pcb->status){
       case OKAY:
          Failover(pcb);
          SetWatchdog();
          break;
       case INITIAL:
       case SUSPECT:
       case REOPEN:
          SetWatchdog();
          break;
       case DOWN:
          break;
       default:
          error("Shouldn't be here!);
          break;
       }
}
STATE         Event                                   Actions                                                       New State
=====         ------                                  -------                                                       ----------
DOWN          Connection down                         CloseConnection()                                             DOWN
DOWN          Connection up                           NumDWA = 0; SendWatchdog(); SetWatchdog(); Pending = TRUE     REOPEN
DOWN          Receive DWA                             Pending = FALSE; Throwaway()                                  DOWN
DOWN          Receive non-DWA                         Throwaway()                                                   DOWN
DOWN          Timer expires                           AttemptOpen(); SetWatchdog()                                  DOWN
INITIAL       Connection down                         CloseConnection(); SetWatchdog()                              DOWN
INITIAL       Connection up                           SetWatchdog()                                                 OKAY
INITIAL       Receive DWA                             Pending = FALSE; Throwaway()                                  INITIAL
INITIAL       Receive non-DWA                         Throwaway()                                                   INITIAL
INITIAL       Timer expires                           AttemptOpen(); SetWatchdog()                                  INITIAL
OKAY          Connection down                         CloseConnection(); Failover(); SetWatchdog()                  DOWN
OKAY          Receive DWA                             Pending = FALSE; SetWatchdog()                                OKAY
OKAY          Receive non-DWA                         SetWatchdog()                                                 OKAY
OKAY          Timer expires & !Pending                SendWatchdog(); SetWatchdog(); Pending = TRUE                 OKAY
OKAY          Timer expires & Pending                 FailOver(); SetWatchdog()                                     SUSPECT
REOPEN        Connection down                         CloseConnection(); SetWatchdog()                              DOWN
REOPEN        Receive DWA & NumDWA < 2                Pending = FALSE; NumDWA++                                     REOPEN
REOPEN        Receive DWA & NumDWA == 2               Pending = FALSE; NumDWA++; Failback()                         OKAY
REOPEN        Receive non-DWA                         Throwaway()                                                   REOPEN
REOPEN        Timer expires & !Pending                SendWatchdog(); SetWatchdog(); Pending = TRUE                 REOPEN
REOPEN        Timer expires & Pending & NumDWA < 0    CloseConnection(); SetWatchdog()                              DOWN
REOPEN        Timer expires & Pending & NumDWA >= 0   NumDWA = -1; SetWatchdog()                                    REOPEN
SUSPECT       Connection down                         CloseConnection(); SetWatchdog()                              DOWN
SUSPECT       Receive DWA                             Pending = FALSE; Failback(); SetWatchdog()                    OKAY
SUSPECT       Timer expires                           CloseConnection(); SetWatchdog()                              DOWN