RFC 3539

Authentication, Authorization and Accounting (AAA) Transport Profile

๐Ÿ“… published June 2003, from ietf

RFC 3539: Authentication, Authorization and Accounting (AAA) Transport Profile ๐ŸŽ€

Okay bestie, this one is RFC 3539, the Authentication, Authorization and Accounting (AAA) Transport Profile ๐Ÿ’…. It was written by B. Aboba from Microsoft and J. Wood from Sun Microsystems, Inc. It's a Standards Track doc, dated June 2003. The title block doesn't list anything it obsoletes or updates, so it's not replacing or patching any older RFC ๐Ÿฆ‹

Status of This Memo ๐Ÿ“œ

This doc specifies a standards track protocol for the Internet community, and it's literally asking for discussion and suggestions for improvements ๐Ÿซถ For the current standardization state and status of this protocol, check the current edition of "Internet Official Protocol Standards" (STD 1). Distribution of this memo is unlimited ๐ŸŒธ

Copyright (C) The Internet Society (2003). All Rights Reserved. ๐Ÿ’œ

Abstract โœจ

This doc talks about the transport issues that show up inside AAA protocols (that's Authentication, Authorization and Accounting, obvi ๐Ÿ™ˆ). It also gives recommendations on how AAA protocols should use transport. It covers standards-track RFCs and experimental proposals, so it's pretty inclusive ๐ŸŒˆ

Table of Contents ๐Ÿ—‚๏ธ

1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  2
    1.1.  Requirements Language. . . . . . . . . . . . . . . . . .  2
    1.2.  Terminology. . . . . . . . . . . . . . . . . . . . . . .  2
2.  Issues in Transport Usage. . . . . . . . . . . . . . . . . . .  5
    2.1.  Application-driven Versus Network-driven . . . . . . . .  5
    2.2.  Slow Failover. . . . . . . . . . . . . . . . . . . . . .  6
    2.3.  Use of Nagle Algorithm . . . . . . . . . . . . . . . . .  7
    2.4.  Multiple Connections . . . . . . . . . . . . . . . . . .  7
    2.5.  Duplicate Detection. . . . . . . . . . . . . . . . . . .  8
    2.6.  Invalidation of Transport Parameter Estimates. . . . . .  8
    2.7.  Inability to use Fast Re-Transmit. . . . . . . . . . . .  9
    2.8.  Congestion Avoidance . . . . . . . . . . . . . . . . . .  9
    2.9.  Delayed Acknowledgments. . . . . . . . . . . . . . . . . 11
    2.10. Premature Failover . . . . . . . . . . . . . . . . . . . 11
    2.11. Head of Line Blocking. . . . . . . . . . . . . . . . . . 11
    2.12. Connection Load Balancing. . . . . . . . . . . . . . . . 12

3.  AAA Transport Profile. . . . . . . . . . . . . . . . . . . . . 12
    3.1.  Transport Mappings . . . . . . . . . . . . . . . . . . . 12
    3.2.  Use of Nagle Algorithm . . . . . . . . . . . . . . . . . 12
    3.3.  Multiple Connections . . . . . . . . . . . . . . . . . . 13
    3.4.  Application Layer Watchdog . . . . . . . . . . . . . . . 13
    3.5.  Duplicate Detection. . . . . . . . . . . . . . . . . . . 19
    3.6.  Invalidation of Transport Parameter Estimates. . . . . . 20
    3.7.  Inability to use Fast Re-Transmit. . . . . . . . . . . . 21
    3.8.  Head of Line Blocking. . . . . . . . . . . . . . . . . . 22
    3.9.  Congestion Avoidance . . . . . . . . . . . . . . . . . . 23
    3.10. Premature Failover . . . . . . . . . . . . . . . . . . . 24
4.  Security Considerations. . . . . . . . . . . . . . . . . . . . 24
5.  IANA Considerations. . . . . . . . . . . . . . . . . . . . . . 25
6.  References . . . . . . . . . . . . . . . . . . . . . . . . . . 25
    6.1.  Normative References . . . . . . . . . . . . . . . . . . 25
    6.2.  Informative References . . . . . . . . . . . . . . . . . 26
Appendix A - Detailed Watchdog Algorithm Description . . . . . . . 28
Appendix B - AAA Agents. . . . . . . . . . . . . . . . . . . . . . 33
    B.1.  Relays and Proxies . . . . . . . . . . . . . . . . . . . 33
    B.2.  Re-directs . . . . . . . . . . . . . . . . . . . . . . . 35
    B.3.  Store and Forward Proxies. . . . . . . . . . . . . . . . 36
    B.4.  Transport Layer Proxies. . . . . . . . . . . . . . . . . 38
Intellectual Property Statement. . . . . . . . . . . . . . . . . . 39
Acknowledgments. . . . . . . . . . . . . . . . . . . . . . . . . . 39
Author Addresses . . . . . . . . . . . . . . . . . . . . . . . . . 40
Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 41

1. Introduction ๐ŸŒธ

Okay so this section is basically the doc introducing itself ๐Ÿ’– It's the same vibe as the abstract: it's about transport issues in AAA protocols, and it gives recommendations on how those protocols use transport. Standards-track RFCs and experimental proposals are both fair game ๐Ÿงš

1.1. Requirements Language ๐Ÿ”‘

Here's where the doc tells you how to read its key words. The words "MAY", "MUST", "MUST NOT", "optional", "recommended", "SHOULD", and "SHOULD NOT" are to be read as described in [RFC2119]. Only the capitalized ones are the official BCP 14 key words, so the capitals are doing the heavy lifting here โญ The lowercase "optional" and "recommended" are just regular words ๐Ÿ™ˆ

1.2. Terminology ๐Ÿ“–

Let's go through the vocab, because this is where the fun lives ๐Ÿฆ‹

Accounting ๐Ÿงพ The act of collecting information on resource usage for the purpose of trend analysis, auditing, billing, or cost allocation.

Administrative Domain ๐Ÿ  An internet, or a collection of networks, computers, and databases under a common administration.

Agent ๐Ÿ•ด๏ธ A AAA agent is an intermediary that communicates with AAA clients and servers. There are several types of AAA agents, including Relays, Re-directs, and Proxies.

Application-driven transport ๐Ÿข Transport behavior is said to be "application-driven" when the rate at which messages are sent is limited by the rate at which the application generates data, rather than by the size of the congestion window. In the most extreme case, the time between transactions exceeds the round-trip time between sender and receiver, which implies the application operates with an effective congestion window of one. AAA transport is typically application driven. ๐Ÿ˜ญ

Attribute Value Pair (AVP) ๐ŸŽ The variable length concatenation of a unique Attribute (represented by an integer) and a Value containing the actual value identified by the attribute.

Authentication ๐Ÿชช The act of verifying a claimed identity, in the form of a pre-existing label from a mutually known name space, as the originator of a message (message authentication) or as the end-point of a channel (entity authentication).

Authorization ๐Ÿ” The act of determining if a particular right, such as access to some resource, can be granted to the presenter of a particular credential.

Billing ๐Ÿ’ธ The act of preparing an invoice.

Network Access Identifier ๐Ÿ†” The Network Access Identifier (NAI) is the userID submitted by the host during network access authentication. In roaming, the purpose of the NAI is to identify the user as well as to assist in the routing of the authentication request. The NAI may not necessarily be the same as the user's e-mail address or the user-ID submitted in an application layer authentication. ๐Ÿ‘€

Network Access Server (NAS) ๐Ÿ›œ A Network Access Server (NAS) is a device that hosts connect to in order to get access to the network.

Proxy ๐Ÿšช In addition to forwarding requests and responses, proxies enforce policies relating to resource usage and provisioning. This is typically done by tracking the state of NAS devices. While proxies typically do not respond to client Requests before receiving a Response from the server, they may originate Reject messages in cases where policies are violated. So proxies need to understand the semantics of the messages passing through them, and they may not support all extensions. ๐Ÿซฃ

Local Proxy ๐Ÿ˜๏ธ A Local Proxy is a proxy that exists within the same administrative domain as the network device (e.g. NAS) that issued the AAA request. Typically a local proxy is used to multiplex AAA messages to and from a large number of network devices, and it may implement policy. ๐Ÿ’…

Store and forward proxy ๐Ÿ“ฆ Store and forward proxies stand out from other proxy species because they send a reply to the NAS before proxying the request to the server. That means store and forward proxies need to implement AAA client and server functionality for the messages they handle. They also typically keep state on conversations in progress so they can make sure proxied Requests and Responses get delivered. While they're most often deployed for accounting, they can also be used to implement authentication/authorization policy. ๐Ÿ”ฅ

Network-driven transport ๐Ÿš€ Transport behavior is said to be "network driven" when the rate at which messages are sent is limited by the congestion window, not by the rate at which the application can generate data. File transfer is an example of an application where transport is network driven. ๐Ÿ“

Re-direct ๐Ÿ‘‰ Rather than forwarding Requests and Responses between clients and servers, Re-directs refer clients to servers and let them communicate directly. Since Re-directs do not sit in the forwarding path, they do not alter any AVPs transiting between client and server. Re-directs do not originate messages and are capable of handling any message type. A Re-direct may be configured to only re-direct messages of certain types, while acting as a Relay or Proxy for other types. As with Relays, re-directs do not keep state with respect to conversations or NAS resources. ๐Ÿฆ‹

Relay ๐Ÿ” Relays forward requests and responses based on routing-related AVPs and domain forwarding table entries. Since relays do not enforce policies, they do not examine or alter non-routing AVPs. So relays never originate messages, do not need to understand the semantics of messages or non-routing AVPs, and are capable of handling any extension or message type. Since relays make decisions based on information in routing AVPs and domain forwarding tables, they do not keep state on NAS resource usage or conversations in progress. ๐Ÿงšโ€โ™€๏ธ


2. Issues in AAA Transport Usage ๐Ÿ’–

Here's the list of transport issues that come up in AAA transport usage. We're going to go through each one in turn, so buckle up ๐ŸŽข

  • Application-driven versus network-driven
  • Slow failover
  • Use of Nagle Algorithm
  • Multiple connections
  • Duplicate detection
  • Invalidation of transport parameter estimates
  • Inability to use fast re-transmit
  • Congestion avoidance
  • Delayed acknowledgments
  • Premature Failover
  • Head of line blocking
  • Connection load balancing

Next up is Section 2.1, Application-driven Versus Network-driven ๐ŸŒˆ

2.1. Application-driven versus Network-driven ๐Ÿฆ‹

okay so AAA transport behavior is usually application driven, not network driven ๐Ÿ’… which means the rate messages get sent is mostly limited by how fast the application generates them, NOT by the size of the congestion window. no cap, that's the main vibe ๐Ÿ˜ญ

let's say we have a 48-port NAS with an average session time of 20 minutes. it only sends about 144 authentication/authorization requests per hour, plus an equal number of accounting requests. that works out to an average inter-packet spacing of 25 seconds, which is way bigger than the RTT (Round Trip Time) in most networks ๐Ÿ™ˆ

even on much bigger NAS devices the spacing is often larger than the RTT. like, take a 2048-port NAS with an average session time of 10 minutes. it sends around 3.4 authentication/authorization requests/second, plus an equivalent number of accounting requests, which gives an average inter-packet spacing of 293 ms โœจ

BUT even when transport is mostly application-driven, network-driven moments can still happen ๐Ÿ‘€ for example, after a NAS reboot, stored accounting records might get sent to the accounting server in rapid succession. similarly, after a power failure, users might all log in at once ๐Ÿ˜ณ in both cases, AAA messages can be generated faster than the network can send them, and a queue builds up ๐ŸŒŠ

network congestion can happen whether transport is network-driven or application-driven. one NAS might not send much AAA traffic, but lots of NASes can all talk to a single AAA proxy or server. so routers close to a heavily loaded proxy or server can get congested, even though traffic from each NAS is light ๐Ÿ˜ฌ this is called "convergent congestion", and it can cause dropped packets in routers near the AAA server, or even inside the AAA server itself ๐Ÿ’€

let's look at 10,000 48-port NASes, each with a 20 minute average session, all configured with the same AAA agent or server. that unlucky proxy or server would get 400 authentication/authorization requests/second, plus an equal number of accounting requests. for 1000 octet requests, that's 6.4 Mbps of incoming traffic at the AAA agent or server ๐Ÿซ 

is this load within the capabilities of the fastest AAA agents and servers? yes โœ… but some implementations just can't handle it ๐Ÿ˜ญ so high queuing delays and/or dropped packets may show up at the agent or server, even when the routers on the path aren't congested at all. which means a well designed AAA protocol needs to handle congestion happening at the AAA server, as well as congestion inside the network ๐Ÿ‘‘

2.2. Slow Failover ๐Ÿƒโ€โ™€๏ธ

where TCP [RFC793] is used as the transport, AAA implementations will have very slow failover times if they wait for a TCP connection to time out before resending on another connection ๐Ÿ˜ฉ this isn't an issue for SCTP [RFC2960], which supports endpoint and path failure detection. as described in section 8 of [RFC2960], once the number of retransmissions goes over the maximum (Association.Max.Retrans), the peer endpoint is considered unreachable, the association enters the CLOSED state, and the failure is reported to the application. this gives us much faster failure detection โšก

2.3. Use of Nagle Algorithm ๐Ÿงƒ

AAA protocol messages are often smaller than the maximum segment size (MSS) ๐Ÿค there are exceptions, like when certificate-based authentication messages are issued or when a low path MTU is found, but typically AAA protocol messages are less than 1000 octets. so, when using TCP [RFC793], you can cut down the total packet count and network overhead by combining multiple AAA messages into a single packet ๐Ÿ“ฆ

where AAA runs over TCP and transport is network-driven, like after a reboot when lots of users log in at once, or when a bunch of stored accounting records need to be sent, the Nagle algorithm ends up doing "transport layer batching" of AAA messages ๐Ÿซถ this doesn't reduce the work the application has to do parsing packets and responding to messages, but it does reduce the number of packets routers along the path have to process. the Nagle algorithm is not used with SCTP ๐Ÿ™…โ€โ™€๏ธ

now, where AAA transport is application-driven, the NAS will typically get a reply from the home server before it has another request to send ๐Ÿ’… which means accounting requests usually get sent individually instead of being batched by the transport layer. so within the application-driven regime, the Nagle algorithm [RFC896] is ineffective ๐Ÿฅฒ

2.4. Multiple Connections ๐Ÿ”Œ

the RADIUS [RFC2865] Identifier field is only a single octet, so a maximum of 256 requests can be in progress between two endpoints described by a 5-tuple: (Client IP address, Client port, UDP, Server IP address, Server port) ๐Ÿคฏ to get around this limit, RADIUS clients have used more than one sending port, sometimes even going to the extreme of using a different UDP source port for each NAS port ๐Ÿ™ˆ

if this behavior got extended to AAA protocols running over reliable transport, the effective slow-start ramp-up would get multiplied by the number of connections. for example, if an AAA client had ten connections open to an AAA agent, and used a per-connection initial window [RFC3390] of 2, then the effective initial window would be 20 ๐Ÿ˜ฌ that's not okay, because it would let the AAA client send a huge burst of packets into the network ๐Ÿ’ฅ

2.5. Duplicate Detection ๐Ÿ‘ฏ

where an AAA client maintains connections to multiple AAA agents or servers, and failover/failback or connection load balancing is supported, it's possible for multiple agents or servers to receive duplicate copies of the same transaction ๐Ÿ˜ณ a transaction may get sent on another connection before the "time wait" interval expires, and that interval is what guarantees all packets sent on the original connection have left the network. so transactions sent on the alternate connection could arrive before the ones sent on the failed connection ๐ŸŒ€ as a result, AAA agents and servers MUST be prepared to handle duplicates, and MUST assume that duplicates can arrive on any connection ๐Ÿซก

for example, in billing, you need to be able to weed out duplicate accounting records, based on the accounting session-id, event-timestamp and NAS identification information ๐Ÿงพ where authentication requests are always idempotent, the resulting duplicate responses from multiple servers will presumably be identical, so not much harm done โœ…

however, there are situations where the response to an authentication request depends on previously established state, like when simultaneous usage restrictions are being enforced ๐Ÿšซ in those cases, authentication requests won't be idempotent. for example, an initial request might get an Accept response, but a duplicate request might get a Reject response from another server, if the user was already presumed to be logged in and only one simultaneous session was allowed ๐Ÿ˜ญ in these situations the AAA client might receive both Accept and Reject responses to the same duplicate request, and the outcome depends on which response arrives first ๐ŸŽฒ

2.6. Invalidation of Transport Parameter Estimates ๐Ÿงฎ

congestion control principles [Congest],[RFC2914] require a transport protocol to be able to respond effectively to congestion, as sensed through increasing delays, packet loss, or explicit congestion notification ๐Ÿ“‰

with network-driven applications, it's possible to respond to congestion on a timescale comparable to the round-trip time (RTT) ๐ŸŽ๏ธ

with AAA protocols though, the time between sends may be longer than the RTT, so network conditions can not be assumed to persist between sends ๐Ÿฅบ for example, the congestion window may grow during a period when congestion is being experienced, because so few packets are sent, which limits the chance for feedback. similarly, after congestion is detected, the congestion window may stay small, even though the network conditions from when congestion happened no longer apply by the time the next packets are sent ๐Ÿ•ฐ๏ธ on top of that, because the sampling interval is so low, estimates of RTT and RTO made via the procedure described in [RFC2988] may become invalid ๐Ÿ™ƒ

2.7. Inability to Use Fast Re-transmit ๐Ÿšซ

when congestion window validation [RFC2861] is implemented, AAA protocols end up operating much of the time in slow-start, with an initial congestion window set to 1 or 2, depending on the implementation [RFC3390] ๐Ÿข this means AAA protocols gain little benefit from the windowing features of reliable transport ๐Ÿ˜”

since the congestion window is so small, it's generally not possible to receive enough duplicate ACKs (3) to trigger fast re-transmit ๐Ÿ™…โ€โ™€๏ธ on top of that, since AAA traffic is two-way, ACKs that include data will not count as part of the duplicate ACKs needed to trigger fast re-transmit. as a result, dropped packets will require a retransmission timeout (RTO) ๐Ÿ’”

2.8. Congestion Avoidance ๐Ÿฆ‹

okay so the law of conservation of packets [Congest] is basically the golden rule of the internet ๐Ÿ’… it says a client shouldn't shove another packet into the network until it's reasonably sure one has already exited the network on the same path. for an AAA client, that means no retransmitting to the same server and no hopping to a different server until it's reasonably sure a packet has left the network on that same path ๐Ÿ‘‘ and if the client moves its window forward as responses roll in, it "self clocks" ๐ŸŽ€ which means it matches its sending speed to whatever bandwidth is actually there. so iconic, no notes.

While a AAA client using a reliable transport such as TCP [RFC793] or SCTP [RFC2960] will self-clock when talking directly to a AAA-server, end-to-end self-clocking is not assured when AAA agents are in the mix ๐Ÿ˜ญ

As described in the Appendix, AAA agents include Relays, Proxies, Re-directs, Store and Forward proxies, and Transport proxies. Of these, only Transport proxies and Re-directs give the AAA client and server a direct transport connection, which means end-to-end self-clocking can actually happen ๐Ÿงš

With Relays, Proxies or Store and Forward proxies, you get two separate and de-coupled transport connections ๐Ÿ“ one runs between the AAA client and the agent, and another runs between the agent and the server. since the two connections are de-coupled, transport layer ACKs don't flow end-to-end, and self-clocking does not occur. it's giving split personality, ngl ๐Ÿ’€

For example, consider what happens when the bottleneck is between a AAA Relay and a AAA server. self-clocking happens between the AAA client and the AAA Relay, so the client adjusts its sending rate to the rate the transport ACKs flow back from the AAA Relay. but that rate is higher than the bottleneck bandwidth, so the overall system won't self-clock. the client just can't see what's going on past the Relay ๐Ÿ™ˆ

Since there's no direct transport connection between the AAA client and AAA server, the AAA client can't estimate the end-to-end transport parameters and adjust its sending rate to the bottleneck bandwidth between the Relay and the server. as a result, the incoming rate at the AAA Relay can be higher than the rate packets can be sent to the AAA server. the Relay is getting flooded, bestie ๐Ÿ˜ฉ

In this case, the end-to-end performance is determined by the details of the agent implementation. in general, end-to-end transport performance with Relays, Proxies or Store and Forward proxies will always be worse in terms of delay and packet loss than if the AAA client and server were talking directly ๐Ÿฅบ

For example, if the agent operates with a large receive buffer, a big queue can build up on the receiving side, since the AAA client can send packets to the agent faster than the agent can send them to the AAA server. eventually the buffer overflows, causing wholesale packet loss as well as high delay. chaos ๐Ÿ”ฅ

Methods to induce fine-grained coupling between the two transport connections are difficult to implement. one possible fix is for the AAA agent to run with a receive buffer that's no larger than its send buffer. then "back pressure" (closing of the receive window) will make the agent slow the AAA client's sending rate when the agent's send buffer fills up ๐Ÿซถ but unless there are multiple connections between the AAA client and AAA agent, closing the receive window affects all the traffic from the AAA client, even traffic going to AAA servers where there's no bottleneck at all. and since multiple connections between a AAA client and agent multiply the effective slow-start ramp rate, this is not recommended. so "back pressure" can't let individual AAA client-server conversations self-clock, and this technique looks impractical for AAA ๐Ÿ™…โ€โ™€๏ธ


2.9. Delayed Acknowledgments ๐ŸŒธ

As described in Appendix B, ACKs can make up as much as half of the traffic generated in an AAA exchange ๐Ÿฅด this happens because AAA conversations are typically application-driven, so there's often not enough traffic to allow ACK piggybacking. as a result, AAA protocols running over TCP or SCTP transport may see a doubling of traffic compared with implementations using UDP transport. not the vibe.

It's typically not possible to fix this through the sockets API. ACK parameters (like the value of the delayed ACK timer) are typically fixed by TCP and SCTP implementations, so the application can't tune them ๐Ÿ”’


2.10. Premature Failover โœˆ๏ธ

RADIUS failover implementations are typically based on primary and secondary servers, where all traffic goes to the primary server unless it's unavailable. however, the failover algorithm was not specified in [RFC2865] or [RFC2866] ๐Ÿคทโ€โ™€๏ธ so RADIUS failover implementations vary in quality, and some fail over prematurely, violating the law of "conservation of packets". major red flag ๐Ÿšฉ

Where a Relay, Proxy or Store and Forward proxy is present, the AAA client has no direct connection to a AAA server and can't estimate the end-to-end transport parameters. as a result, a AAA client waiting for an application-layer response from the server has no transport-based mechanism for picking an appropriate failover timer ๐Ÿ˜ตโ€๐Ÿ’ซ

For example, if the path between the AAA agent and server includes a high delay link, or if the AAA server is very heavily loaded, the NAS might fail over to another agent while packets are still in flight. this breaks the principle of "conservation of packets", since the AAA client injects additional packets into the network before it has evidence that a previously sent packet has left. that can make an already congested link even worse, leading to congestive collapse [Congest] ๐Ÿ’”


2.11. Head of Line Blocking ๐Ÿšง

Head of line blocking happens during periods of packet loss when the time between sends is shorter than the re-transmission timeout value (RTO) โฑ๏ธ in those situations, packets back up in the send queue until the lost packet can be successfully re-transmitted. this can be an issue for SCTP when using ordered delivery over a single stream, and for TCP.

Head of line blocking is typically only an issue on larger NASes ๐Ÿ’… for example, a 48-port NAS with an average inter-packet spacing of 25 seconds is unlikely to have an RTO greater than that, unless severe packet loss has been experienced. but a 2048-port NAS with an average inter-packet spacing of 293 ms may experience head-of-line blocking, since that spacing is less than the minimum RTO value of 1 second [RFC2988] ๐Ÿ˜ฑ


2.12. Connection Load Balancing โš–๏ธ

To lessen queuing delays and address head of line blocking, an AAA implementation may want to load balance between connections to multiple destinations โœจ dynamic load balancing techniques are possible, but this level of sophistication may not be required. in lots of situations, adequate reliability and load balancing can be achieved with static load balancing, where traffic is spread across destinations based on static "weights" ๐ŸŽ€


3. AAA Transport Profile ๐Ÿ’œ

To address AAA transport issues, it is recommended that AAA protocols make use of standards track as well as experimental techniques ๐Ÿงš more details are in the sections that follow.


3.1. Transport Mappings ๐Ÿ”Œ

AAA Servers MUST support TCP and SCTP. AAA clients SHOULD support SCTP, but MUST support TCP if SCTP is not available. as SCTP support improves, it's possible that SCTP support will be required on clients at some point in the future ๐ŸŒˆ AAA agents inherit all the obligations of Servers with respect to transport support, so they're on the hook too ๐Ÿซก


3.2. Use of Nagle Algorithm ๐Ÿผ

While AAA protocols typically operate in the application-driven regime, there are circumstances where they're network driven. for example, when an NAS reboots, or when connectivity is restored between an NAS and a AAA agent, multiple packets might be available for sending all at once ๐Ÿ’ฅ

So there are circumstances where the transport-layer batching provided by the Nagle Algorithm (12) is useful, which is why AAA implementations running over TCP MUST enable the Nagle algorithm, [RFC896]. the Nagle algorithm is not used with SCTP ๐Ÿ™Œ


3.3. Multiple Connections ๐Ÿซง

AAA protocols SHOULD use only a single persistent connection between a AAA client and a AAA agent or server ๐Ÿ’– they SHOULD also provide for pipelining of requests, so more than one request can be in progress at a time ๐Ÿƒโ€โ™€๏ธ to minimize use of inactive connections in roaming situations, a AAA client or agent MAY bring down a connection to a AAA agent or server if the connection has been unutilized (discounting the watchdog) for a certain period of time, which MUST NOT be less than BRINGDOWN_INTERVAL (5 minutes) โณ

While a AAA client/agent SHOULD only use a single persistent connection to a given AAA agent or server, it MAY have connections to multiple AAA agents or servers ๐Ÿฆ‹ a AAA client/agent connected to multiple agents/servers can treat them as primary/secondary or balance load between them ๐ŸŽ€

3.4. Application Layer Watchdog ๐Ÿฆ‹

okay so, to help AAA implementations catch transport and application-layer failures faster, AAA protocols MUST support an application layer watchdog message. ๐Ÿ’…

The application layer watchdog message lets you fail over from a peer that's gone down, either because it's unreachable or because its application functions have failed. ๐Ÿซถ This is different from the SCTP heartbeat, which is all about failing over between interfaces. The SCTP heartbeat might get you onto another path to the same server, but it can't handle the server system or the application service dying. ๐Ÿ’€ So both mechanisms MAY be used together. โœจ

The watchdog is how an AAA client or agent figures out when to resend on another connection. ๐Ÿงš It runs on all open connections, and it's used to suspend and eventually close the ones that are having trouble. It also re-opens and validates connections that have come back to health. The watchdog may be used in primary/secondary or load balancing setups. However, it is not intended as a cluster heartbeat mechanism.

โš ๏ธ Don't treat the watchdog like a cluster heartbeat. It's a per-peer check, not a cluster health tool.

The application layer watchdog is designed to detect failures of the immediate peer, and not to be affected by failures of downstream proxies or servers. ๐Ÿ›ก๏ธ This stops instability in downstream AAA components from bubbling upstream. Receiving any AAA Response from a peer counts as proof that the peer is up, but a missing Response isn't enough to say the peer is down. A missing Response could be caused by a problem with a downstream proxy or server, so a peer is only determined to be down after it fails to answer the watchdog message. ๐Ÿ™ˆ

Because the watchdog counts any AAA Response toward peer liveness, shrinking the watchdog timer interval doesn't significantly increase watchdog traffic on heavily loaded networks. ๐Ÿ“ˆ That's because watchdog messages don't need to be sent when other AAA Response traffic is constantly reminding everyone the peer is alive. Watchdog traffic only goes up when AAA traffic is light, so there's no AAA Response "signal" around. Still, lowering the timer interval TWINIT does increase the probability of false failover significantly, so make that decision with care. ๐Ÿฅน


3.4.1. Algorithm Overview โœจ

The watchdog behavior is controlled by an algorithm defined in this section. ๐Ÿง  This algorithm is appropriate for primary/secondary or load balancing configurations. Implementations SHOULD implement this algorithm, which works like this:

[1] Watchdog behavior is controlled by a single timer (Tw). The initial value of Tw, before jittering, is Twinit. The default value of Twinit is 30 seconds. That value was picked because it minimizes the probability that failover gets kicked off by a routing flap, as noted in [Paxson].

While Twinit MAY be set as low as 6 seconds (not including jitter), it MUST NOT be set lower than this. Heads up, bestie: setting it that low is likely to raise the probability of duplicates, along with spurious failover and failback attempts. ๐Ÿ˜ฌ

To avoid synchronization behaviors that can happen with fixed timers among distributed systems, every time the watchdog interval is calculated, it gets jitter. You take the Twinit value and randomly add a value drawn between -2 and 2 seconds. Alternative calculations to create jitter MAY be used. These MUST be pseudo-random, generated by a PRNG seeded as per [RFC1750]. ๐ŸŽฒ

[2] When any AAA message is received, Tw is reset. That doesn't have to be a response to a watchdog request. Receiving a watchdog response from a peer counts as activity, and Tw should be reset. If the watchdog timer expires and no watchdog response is pending, then a watchdog message is sent. On sending a watchdog request, Tw is reset.

Watchdog packets are not retransmitted by the AAA protocol, since AAA protocols run over reliable transports that handle all retransmissions internally. So a watchdog request is only sent when there is no watchdog response pending. ๐Ÿ”

[3] If the watchdog timer expires and a watchdog response is pending, then failover is initiated. For a AAA client or agent to perform failover procedures, it needs to maintain a pending message queue for a given peer. When an answer message is received, the corresponding request is removed from the queue. The Hop-by-Hop Identifier field MAY be used to match the answer with the queued request.

When failover is initiated, all messages in the queue are sent to an alternate agent, if one is available. Multiple identical requests or answers may be received as a result of a failover. The combination of an end-to-end identifier and the origin host MUST be used to identify duplicate messages. ๐Ÿ‘ฏ

Note that where traffic is heavy, the application layer watchdog can take as long as 2Tw to determine that a peer has gone down. For peers receiving a high volume of AAA Requests, AAA Responses keep resetting the timer, so after a failure it takes Tw for the lack of traffic to be noticed and for the watchdog message to be sent. Then another Tw elapses before failover is initiated. ๐Ÿข

On a lightly loaded network without much AAA Response traffic, the watchdog timer will typically expire without being reset, so a watchdog response will be outstanding, and failover will be initiated after only a single timer interval has expired. โฑ๏ธ

[4] The client MUST NOT close the primary connection until the primary's watchdog timer has expired at least twice without a response (note that the watchdog is not sent a second time, however). Once this has occurred, the client SHOULD cause a transport reset or close to be done on the connection.

Once the primary connection has failed, subsequent requests are sent to the alternate server until the watchdog timer on the primary connection is reset.

Suspension of the primary connection prevents flapping between primary and alternate connections, and ensures that failover behavior remains consistent. The application may not receive a response to the watchdog request message due to a connectivity problem, in which case a transport layer ACK will not have been received, or the lack of response may be due to an application problem. Without transport layer visibility, the application is unable to tell the difference, so it has to behave conservatively. ๐Ÿฅบ

In situations where no transport layer ACK is received on the primary connection after multiple re-transmissions, the RTO will be exponentially backed off as described in [RFC2988]. Due to Karn's algorithm as implemented in SCTP and TCP, the RTO estimator will not be reset until another ACK is received in response to a non-re-transmitted request. So in cases where the problem occurs at the transport layer, after the client fails over to the alternate server, the RTO of the primary will remain at a high value unless an ACK is received on the primary connection. ๐Ÿ“‰

In the case where the problem occurs at the transport layer, subsequent requests sent on the primary connection will not receive the same service as was originally provided. For example, instead of failover occurring after 3 retransmissions, failover might occur without even a single retransmission if RTO has been sufficiently backed off. Of course, if the lack of a watchdog response was due to an application layer problem, then RTO will not have been backed off. However, without transport layer visibility, there is no way for the application to know this. ๐Ÿคทโ€โ™€๏ธ

Suspending use of the primary connection until a response to a watchdog message is received guarantees that the RTO timer will have been reset before the primary connection is reused. If no response is received after the second watchdog timer expiration, then the primary connection is closed and the suspension becomes permanent. ๐Ÿ”’

[5] While the connection is in the closed state, the AAA client MUST NOT attempt to send further watchdog messages on the connection. However, after the connection is closed, the AAA client continues to periodically attempt to reopen the connection.

The AAA client SHOULD wait for the transport layer to report connection failure before attempting again, but MAY choose to bound this wait time by the watchdog interval, Tw. If the connection is successfully opened, then the watchdog message is sent. Once three watchdog messages have been sent and responded to, the connection is returned to service, and transactions are once again sent over it. Connection validation via receipt of multiple watchdogs is not required when a connection is initially brought up -- in this case, the connection can immediately be put into service. ๐ŸŽ‰

[6] When using SCTP as a transport, it is not necessary to disable SCTP's transport-layer heartbeats. However, if AAA implementations have access to SCTP's heartbeat parameters, they MAY choose to ensure that SCTP's heartbeat interval is longer than the AAA watchdog interval, Tw. This makes sure alternate paths are still probed by SCTP, while the primary path has a minimum of heartbeat redundancy. ๐ŸŒˆ

3.4.2. Primary/Secondary Failover Support โœจ

okay so the watchdog timer MAY be hooked up with primary/secondary style failover ๐Ÿ”, which gives you better reliability and basic load balancing ๐Ÿ’–. to share the work, each AAA server is the primary for a chunk of clients and a secondary (at varying priority) for the rest. that's how the load gets spread around ๐Ÿซถ

Within primary/secondary setups, the watchdog timer works like this:

  1. every client or agent starts out configured with one primary agent or server, plus one or more secondary connections ๐ŸŒธ
  2. the watchdog is what suspends and eventually closes primary connections that are having a rough time ๐Ÿ˜ญ. it's also what re-opens and validates connections that have bounced back to health โœจ
  3. once a secondary gets promoted to primary (temporarily or for good ๐Ÿ‘‘), the next server on the secondaries list gets promoted to fill the open secondary slot ๐Ÿงš
  4. clients and agents periodically try to re-open closed connections, so a previously closed connection can come back into service and be eligible again ๐Ÿฆ‹. implementations usually keep a cap on how many connections are open at once, so when a closed one comes back online, the lowest priority secondary connection gets closed. to stop secondaries from endlessly closing and re-opening, it is recommended that working connections stay open for a minimum of 5 minutes ๐Ÿ•”
  5. to diagnose failover behavior, it is recommended that a table of failover events be kept within the MIB ๐Ÿ“. these failover events SHOULD include appropriate transaction identifiers, so client and server data can be compared. that gives you insight into whether the problem is at the transport or application layer ๐Ÿ”

3.4.3. Connection Load Balancing ๐Ÿ’œ

Primary/secondary failover gives you improved resilience and basic load balancing, but it doesn't fix TCP head of line blocking ๐Ÿ™ˆ, since only a single connection is in use at a time.

A AAA client or agent that maintains connections to multiple agents or servers MAY load balance between them. Connecting to several agents or servers reduces head of line blocking on TCP connections, but doesn't eliminate it. That issue doesn't exist with SCTP connections using multiple streams ๐ŸŒˆ

In connection load balancing setups, the application watchdog works like this:

  1. every client or agent starts out configured with connections to multiple AAA agents or servers, with one connection between a given client/agent and a given agent/server ๐Ÿงฉ
  2. in static load balancing, transactions are split across the connections based on the total number of connections and a "weight" assigned to each one. Pearson's hash [RFC3074] applied to the NAI [RFC2486] can decide which connection handles a given transaction. hashing on the NAI gives super granular load balancing while making sure all traffic for a conversation goes to the same agent or server ๐Ÿ’…. in dynamic load balancing, the "weight" can change based on things like AAA server load. those techniques are sophisticated, but they're out of scope for this doc ๐Ÿค“
  3. transactions get distributed based on the total number of available connections and their weights. a change in the number of available connections forces the hash table to be recomputed. so conversations in progress don't get switched to new destinations, there has to be a transitional period where both the old and new hash tables are needed, so conversations can age out. this requires a way to tell whether a Request is a new conversation or the continuation of an existing one ๐Ÿ‘€. removing and adding connections is an expensive operation, so it is recommended that the hash table only be recomputed once a connection is closed or returned to service.

Suspended connections, even though they aren't used, don't force a hash table reconfiguration until they're closed. Likewise, re-opened connections that aren't accumulating enough watchdog responses don't force a reconfiguration until they're returned to service ๐Ÿซง.

While a connection is suspended, transactions meant for it get assigned to the next available server instead. yes, that causes a momentary imbalance, but it's felt to be a relatively small price to pay to reduce hash table thrashing ๐Ÿ’–.

  1. to diagnose load balancing behavior, it is recommended that, in addition to a table of failover events, a table of statistics be kept on each client, indexed by a AAA server. that way, the effectiveness of the load balancing algorithm can be evaluated ๐Ÿ“Š

3.5. Duplicate Detection ๐ŸŽฏ

Multiple facilities are required to enable duplicate detection. these include session identifiers, plus hop-by-hop and end-to-end message identifiers. hop-by-hop identifiers whose value may change at each hop are not enough ๐Ÿ™…, because a AAA server may receive the same message from multiple agents. for example, a AAA client can send a request to Agent1, fail over, and resend the request to Agent2. both agents forward the request to the home AAA server, each with a different hop-by-hop identifier. a Session Identifier isn't enough either, since it doesn't distinguish different messages for the same session.

Proper treatment of the end-to-end message identifier ensures that AAA operations are idempotent โœจ. for example, without an end-to-end identifier, a AAA server keeping track of simultaneous logins might send an Accept in response to an initial Request, and then a Reject in response to a duplicate Request (where the user was allowed only one simultaneous login). depending on which Response arrived first, the user might be allowed access or not ๐Ÿ˜ฌ.

However, if the server stores the end-to-end message identifier along with the simultaneous login information, then the duplicate Request (which uses the same end-to-end message identifier) can be identified, and the correct response can be returned ๐Ÿซถ.

3.6. Invalidation of Transport Parameter Estimates ๐Ÿงฎ

To address invalidation of transport parameter estimates, AAA protocol implementations MAY use Congestion Window Validation [RFC2861] and RTO validation when using TCP. This specification also recommends a procedure for RTO validation.

[RFC2581] and [RFC2861] both recommend that a connection go into slow-start after a period where no traffic has been sent within the RTO interval. [RFC2861] recommends only increasing the congestion window if it was full when the ACK arrived. The congestion window is reduced by half once every RTO interval if no traffic is received.

When Congestion Window Validation is used, the congestion window won't build during application-driven periods. instead, it gets decayed. so AAA applications operating in the application-driven regime will typically run with a congestion window equal to the initial window much of the time, basically "perpetual slowstart" ๐Ÿข.

During periods where AAA behavior is application-driven, this has no effect. since the time between packets is larger than RTT, AAA operates with an effective congestion window equal to the initial window. but during network-driven periods, the effect is to space out the sending of AAA packets. so instead of blasting a big burst into the network, a client needs to wait several RTTs while the congestion window builds during slow-start โณ.

For example, a client operating over TCP with an initial window of 2, with 35 AAA requests to send, would take approximately 6 RTTs to send them, as the congestion window builds during slow start: 2, 3, 3, 6, 9, 12. after the backlog is cleared, the implementation is application-driven again and the congestion window size decays. if the client were using SCTP, the number of RTTs needed would usually be less, and would depend on the size of the requests, since SCTP tracks the progress of opening the congestion window by bytes, not segments ๐Ÿ’ซ.

Note that [RFC2861] and [RFC2988] do not address the issue of RTO validation. this is also a problem, particularly when the Congestion Manager [RFC3124] is implemented ๐Ÿšจ. during periods of high packet loss, the RTO may be repeatedly increased via exponential back-off, and may reach a high value. because there's little timely feedback on RTT and RTO during application-driven periods, that high RTO estimate can stick around long after the conditions that created it have dissipated ๐Ÿ˜ฉ.

RTO validation MAY be used to address this issue for TCP, via the following procedure:

After the congestion window is decayed according to [RFC2861], reset the estimated RTO to 3 seconds. After the next packet comes in, re-calculate RTTavg, RTTdev, and RTO according to the method described in [RFC2581].

To address this issue for SCTP, AAA implementations SHOULD use SCTP heartbeats. [RFC2960] states that heartbeats should be enabled by default, with an interval of 30 seconds. if that interval proves to be too long to resolve this issue, AAA implementations MAY reduce the heartbeat interval ๐Ÿ’“.

3.7. Inability to Use Fast Re-Transmit ๐Ÿƒ

When Congestion Window Validation [RFC2861] is used, AAA implementations will operate with a congestion window equal to the initial window much of the time. so the window size will often not be large enough to enable fast re-transmit for TCP. plus, since AAA traffic is two-way, ACKs carrying data will not count towards triggering fast re-transmit ๐Ÿ™ƒ. SCTP is less likely to encounter this issue, so the measures described below apply to TCP.

To address this issue, AAA implementations SHOULD support selective acknowledgement as described in [RFC2018] and [RFC2883]. AAA implementations SHOULD also implement Limited Transmit for TCP, as described in [RFC3042]. rather than reducing the number of duplicate ACKs required to trigger fast recovery (which would increase the number of inappropriate re-transmissions), Limited Transmit enables the window size to be increased. that lets additional packets get sent, which in turn may trigger fast re-transmit without a change to the algorithm โœจ.

However, if congestion window validation [RFC2861] is implemented, this proposal will only have an effect in situations where the time between packets is less than the estimated retransmission timeout (RTO). if the time between packets is greater than RTO, additional packets will typically not be available for sending to take advantage of the increased window size. as a result, AAA protocols will typically operate with the lowest possible congestion window size, resulting in a re-transmission timeout for every lost packet ๐Ÿ’€.

3.8. Head of Line Blocking ๐Ÿงš

okay so TCP literally does not solve head-of-line blocking ๐Ÿ’€ but its effects can be lessened by Limited Transmit [RFC3042] and by connection load balancing ๐ŸŽ€

3.8.1. Using SCTP Streams to Prevent Head of Line Blocking ๐Ÿฆ‹

Each AAA node SHOULD spread its messages evenly across the range of SCTP streams that it and its peer have agreed on ๐ŸŒˆ (that way, a lost message in one stream won't make every other stream block too). The easiest way to do this is to keep a counter for the stream ID you send on. When the counter hits the maximum number of streams for the association, it resets to 0 ๐Ÿ’…

AAA peers MUST be able to accept messages on any stream โœจ Streams are used solely to stop head-of-the-line blocking. All of the identifying info lives inside the Diameter payload, so messages spread across multiple streams might not arrive in the order they were sent ๐Ÿ™ˆ

SCTP peers can allocate up to 65535 streams for an association. The cost of idle streams may or may not be zero depending on the implementation, but the cost of non-idle streams is always greater than 0. So admins may want to limit how many streams their Diameter nodes can have, based on the resources (memory, CPU power, etc.) of each node ๐Ÿ“

On a Diameter client, the number of streams can be based on the maximum number of peak users on the NAS. If each user gets a stream, that should be enough to prevent head-of-line blocking ๐Ÿ‘‘ On a Diameter proxy, the number of streams can be based on the maximum number of peak sessions in progress from that proxy to each downstream AAA server.

Stream IDs don't have to be preserved by relay agents, which keeps things simple, because agents can easily forward between two associations that have different numbers of streams ๐Ÿง  Here's an example: a relay server DRL forwards messages between a NAS and a home server, HMS. The NAS and DRL agreed on 1000 streams for their association, and DRL and HMS agreed on 2000 streams for theirs. This is the message flow from NAS to HMS via DRL, along with the stream ID for each message:

+------+                   +------+                   +------+
|      |                   |      |                   |      |
| NAS  |    --------->     | DRL  |     --------->    | HMS  |
|      |                   |      |                   |      |
+------+   1000 streams    +------+    2000 streams   +------+

           msg 1: str id 0             msg 1: str id 0
           msg 2: str id 1             msg 2: str id 1
           ...
           msg 1000: str id 999        msg 1000: str id 999
           msg 1001: str id 0          msg 1001: str id 1000

DRL can forward messages 1 through 1000 to HMS using the same stream ID that NAS used to send to DRL. But since the NAS / DRL association only has 1000 streams, NAS wraps around to stream ID 0 when it sends message 1001. The DRL / HMS association has 2000 streams, though, so DRL can give message 1001 stream ID 1000 when it forwards it on to HMS ๐ŸŽ‰

This distribution scheme works kind of like a hash table. It's possible (but unlikely) that two messages end up in the same stream, and it's even less likely that message loss causes blocking when that happens. If it does turn out to be a problem, local administrators can increase the number of streams on their nodes to improve performance ๐Ÿ’–

3.9. Congestion Avoidance ๐ŸŒธ

To improve on the default timer estimates, AAA implementations MAY implement the Congestion Manager (CM) [RFC3124]. CM is an end-system module that:

  • (i) enables an ensemble of multiple concurrent streams from a sender destined to the same receiver, sharing the same congestion properties, to perform proper congestion avoidance and control, and
  • (ii) allows applications to easily adapt to network congestion.

CM helps integrate congestion management across all applications and transport protocols ๐Ÿซถ It keeps track of congestion parameters (available aggregate and per-stream bandwidth, per-receiver round-trip times, etc.) and exports an API so applications can learn about network characteristics, pass information to CM, share congestion information with each other, and schedule data transmissions.

CM lets the AAA application access transport parameters (RTTavg, RTTdev) through callbacks. RTO estimates aren't available through the callback interface right now, even though they probably should be ๐Ÿ˜ญ Wherever transport parameters are available, they SHOULD be used to improve on the default timer values โญ

3.10. Premature Failover ๐Ÿ™…โ€โ™€๏ธ

Premature failover is prevented by the watchdog functionality described above. If the next hop doesn't send back a reply, the AAA client sends it a watchdog message to check that it's alive. If a watchdog reply comes back, the AAA client knows the next hop server is working at the application layer โœจ Because of that, only terminal error messages are needed, such as these:

  • "Busy": agent/Server too busy to handle additional requests, NAS should failover all requests to another agent/server.
  • "Can't Locate": agent can't locate the AAA server for the indicated realm; NAS should failover that request to another proxy.
  • "Can't Forward": agent has tried both primary and secondary AAA servers with no response; NAS should failover the request to another agent.
These messages have different scopes, so they matter ๐Ÿ‘€ The "Busy" message tells the NAS that the agent/server is too busy for ANY request. The "Can't Locate" and "Can't Forward" messages mean the ultimate destination can't be reached or isn't responding, which implies per-request failover.

4. Security Considerations ๐Ÿ”

Since AAA clients, agents and servers act as network access gatekeepers, they're super tempting targets for attackers ๐Ÿ˜ˆ General security considerations for TCP congestion control are covered in [RFC2581]. There are some extra considerations that apply to this specification, though, so pay attention!

By enabling failover between AAA agents, this specification makes AAA applications more resilient. But it may also open up avenues for denial of service attacks ๐Ÿ’€

The failover algorithm is driven by a lack of response to AAA requests and watchdog packets. On a lightly loaded network where AAA responses wouldn't come back before the watchdog timer expires, an attacker can swamp the network so watchdog packets get dropped. That makes the AAA client switch to another AAA agent, where the attack can be repeated. By making the AAA client cycle between AAA agents, an attacker can deny service to users who want network access ๐Ÿฅบ

Where TLS [RFC2246] is used to provide AAA security, there's a vulnerability to spoofed reset packets, along with other transport layer denial of service attacks (e.g. SYN flooding). Since SCTP offers better denial of service resilience than TCP, this can be mitigated to some extent where AAA applications run over SCTP ๐Ÿ›ก๏ธ

Where IPsec [RFC2401] is used to provide security, it's really important that IPsec policy requires IPsec on incoming packets. To let an AAA client figure out which security mechanisms an agent or server uses without any prior knowledge, it may be tempting to start a connection in the clear and then have the AAA agent respond with IKE [RFC2409]. That approach cuts down on required client configuration, but it makes denial of service attacks easier, since a connection request can now tie up not only transport resources but also resources inside the IKE implementation ๐Ÿšจ

5. IANA Considerations ๐Ÿ“‹

This document does not create any new number spaces for IANA administration.

References ๐Ÿ“š

6.1. Normative References

[RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC 793, September 1981.

[RFC896] Nagle, J., "Congestion Control in IP/TCP internetworks", RFC 896, January 1984.

[RFC1750] Eastlake, D., Crocker, S. and J. Schiller, "Randomness Recommendations for Security", RFC 1750, December 1994.

[RFC2018] Mathis, M., Mahdavi, J., Floyd, S. and A. Romanow, "TCP Selective Acknowledgment Options", RFC 2018, October 1996.

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC2486] Aboba, B. and M. Beadles, "The Network Access Identifier", RFC 2486, January 1999.

[RFC2581] Allman, M., Paxson, V. and W. Stevens, "TCP Congestion Control", RFC 2581, April 1999.

[RFC2883] Floyd, S., Mahdavi, J., Mathis, M., Podolsky, M. and A. Romanow, "An Extension to the Selective Acknowledgment (SACK) Option for TCP", RFC 2883, July 2000.

[RFC2960] Stewart, R., Xie, Q., Morneault, K., Sharp, C., Schwarzbauer, H., Taylor, T., Rytina, I., Kalla, M., Zhang, L. and V. Paxson, "Stream Control Transmission Protocol", RFC 2960, October 2000.

[RFC2988] Paxson, V. and M. Allman, "Computing TCP's Retransmission Timer", RFC 2988, November 2000.

[RFC3042] Allman, M., Balakrishnan H. and S. Floyd, "Enhancing TCP's Loss Recovery Using Limited Transmit", RFC 3042, January 2001.

[RFC3074] Volz, B., Gonczi, S., Lemon, T. and R. Stevens, "DHC Load Balancing Algorithm", RFC 3074, February 2001.

[RFC3124] Balakrishnan, H. and S. Seshan, "The Congestion Manager", RFC 3124, June 2001.

6.2. Informative References

[RFC2246] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC 2246, January 1999.

[RFC2401] Atkinson, R. and S. Kent, "Security Architecture for the Internet Protocol", RFC 2401, November 1998.

[RFC2409] Harkins, D. and D. Carrel, "The Internet Key Exchange (IKE)", RFC 2409, November 1998.

[RFC2607] Aboba, B. and J. Vollbrecht, "Proxy Chaining and Policy Implementation in Roaming", RFC 2607, June 1999.

[RFC2861] Handley, M., Padhye, J. and S. Floyd, "TCP Congestion Window Validation", RFC 2861, June 2000.

[RFC2865] Rigney, C., Willens, S., Rubens, A. and W. Simpson, "Remote Authentication Dial In User Service (RADIUS)", RFC 2865, June 2000.

[RFC2866] Rigney, C., "RADIUS Accounting", RFC 2866, June 2000.

[RFC2914] Floyd, S., "Congestion Control Principles", BCP 41, RFC 2914, September 2000.

[RFC2975] Aboba, B., Arkko, J. and D. Harrington, "Introduction to Accounting Management", RFC 2975, June 2000.

[RFC3390] Allman, M., Floyd, S. and C. Partridge, "Increasing TCP's Initial Window", RFC 3390, October 2002.

[Congest] Jacobson, V., "Congestion Avoidance and Control", Computer Communication Review, vol. 18, no. 4, pp. 314-329, Aug. 1988. ftp://ftp.ee.lbl.gov/papers/congavoid.ps.Z

[Paxson] Paxson, V., "Measurement and Analysis of End-to-End Internet Dynamics", Ph.D. Thesis, Computer Science Division, University of California, Berkeley, April 1997.

Appendix A - Detailed Watchdog Algorithm โœจ

okay so in this appendix, we're calling the memory control structure that holds everything about one specific peer a Peer Control Block, or PCB for short ๐Ÿงš it's literally the single source of truth for each peer. The PCB has these fields:

  • Status, which can be:
    • OKAY: The connection is up
    • SUSPECT: Failover has been initiated on the connection.
    • DOWN: Connection has been closed.
    • REOPEN: Attempting to reopen a closed connection
    • INITIAL: The initial state of the pcb when it is first created. The pcb has never been opened.
  • Variables, which are:
    • Pending: Set to TRUE if there is an outstanding unanswered watchdog request
    • Tw: Watchdog timer value
    • NumDWA: Number of DWAs received during REOPEN

Tw is the watchdog timer, and it's measured in seconds ๐Ÿ’… every second, Tw gets decremented. When it hits 0, the OnTimerElapsed event (see below) gets invoked. The pseudo-code for the whole algorithm is right below, so read it like a group chat thread ๐Ÿ“

SetWatchdog()
{
/*
 SetWatchdog() is called whenever it is necessary
 to reset the watchdog timer Tw.  The value of the
 watchdog timer is calculated based on the default
 initial value TWINIT and a jitter ranging from
 -2 to 2 seconds.  The default for TWINIT is 30 seconds,
 and MUST NOT be set lower than 6 seconds.
*/
    Tw=TWINIT -2.0 + 4.0 * random() ;
    SetTimer(Tw) ;
    return ;
}

/*
 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(pcb);
             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 SUSPECT:
       case REOPEN:
          SetWatchdog();
          break;
       default:
          error("Shouldn't be here!);
          break;
       }
}

Here's the state machine that's basically the same as all that code, so if you're a visual person, this one's for you ๐Ÿฆ‹

STATE         Event                Actions              New State
=====         ------               -------              ----------
OKAY          Receive DWA          Pending = FALSE
                                   SetWatchdog()        OKAY
OKAY          Receive non-DWA      SetWatchdog()        OKAY
SUSPECT       Receive DWA          Pending = FALSE
                                   Failback()
                                   SetWatchdog()        OKAY
SUSPECT       Receive non-DWA      Failback()
                                   SetWatchdog()        OKAY
REOPEN        Receive DWA &        Pending = FALSE
              NumDWA == 2          NumDWA++
                                   Failback()           OKAY
REOPEN        Receive DWA &        Pending = FALSE
              NumDWA < 2           NumDWA++             REOPEN

STATE         Event                Actions              New State
=====         ------               -------              ----------
REOPEN        Receive non-DWA      Throwaway()          REOPEN
INITIAL       Receive DWA          Pending = FALSE
                                   Throwaway()          INITIAL
INITIAL       Receive non-DWA      Throwaway()          INITIAL
DOWN          Receive DWA          Pending = FALSE
                                   Throwaway()          DOWN
DOWN          Receive non-DWA      Throwaway()          DOWN
OKAY          Timer expires &      SendWatchdog()
              !Pending             SetWatchdog()
                                   Pending = TRUE       OKAY
OKAY          Timer expires &      Failover()
              Pending              SetWatchdog()        SUSPECT
SUSPECT       Timer expires        CloseConnection()
                                   SetWatchdog()        DOWN
INITIAL       Timer expires        AttemptOpen()
                                   SetWatchdog()        INITIAL
DOWN          Timer expires        AttemptOpen()
                                   SetWatchdog()        DOWN
REOPEN        Timer expires &      SendWatchdog()
              !Pending             SetWatchdog()
                                   Pending = TRUE       REOPEN
REOPEN        Timer expires &      CloseConnection()
              Pending &            SetWatchdog()
              NumDWA < 0                                DOWN
REOPEN        Timer expires &      NumDWA = -1
              Pending &            SetWatchdog()
              NumDWA >= 0                               REOPEN
INITIAL       Connection up        SetWatchdog()        OKAY
DOWN          Connection up        NumDWA = 0
                                   SendWatchdog()
                                   SetWatchdog()
                                   Pending = TRUE       REOPEN
OKAY          Connection down      CloseConnection()
                                   Failover()
                                   SetWatchdog()        DOWN
SUSPECT       Connection down      CloseConnection()
                                   SetWatchdog()        DOWN
REOPEN        Connection down      CloseConnection()
                                   SetWatchdog()        DOWN

Appendix B - AAA Agents ๐ŸŒธ

okay bestie, so as described in [RFC2865] and [RFC2607], AAA agents have gotten super popular for supporting stuff like roaming and shared use networks ๐ŸŒˆ these agents do the authentication/authorization part, and they also handle accounting [RFC2975]. literally the whole support squad ๐Ÿซถ

AAA agents come in these flavors:

  • Relays
  • Proxies
  • Re-directs
  • Store and Forward proxies
  • Transport layer proxies

The transport layer behavior of each of these agents is described below โœจ

B.1 Relays and Proxies โœจ

Okay so, relays and proxies act differently at the application layer, but bestie, at the transport layer they behave pretty much the same ๐Ÿ’…. In both cases there are two connections: one from the AAA client (NAS) to the relay/proxy, and another from the relay/proxy to the AAA server. The relay/proxy doesn't answer the client's request until it hears back from the server. Because those two connections are decoupled, the end-to-end conversation might not self clock ๐ŸŒธ.

AAA transport is usually application-driven, so there's often not enough traffic for ACK piggybacking to happen ๐Ÿฆ‹. That means the Nagle algorithm rarely kicks in, and delayed ACKs can make up nearly half the traffic. So AAA protocols running over reliable transport end up sending almost double the packets you'd see with UDP transport ๐Ÿ˜ญ. The ACK parameters, like the delayed ACK timer, are set by the TCP implementation and can't be tuned by the application, so there's honestly not much we can do about it ๐Ÿ™ˆ.

Here's a typical trace of a conversation between a NAS, a proxy, and a server:

Time            NAS           Relay/Proxy           Server
------          ---           -----------           ------

0               Request
                ------->
OTTnp + Tpr                     Request
                                ------->

OTTnp + TdA                     Delayed ACK
                                <-------

OTTnp + OTTps +                                 Reply/ACK
Tpr + Tsr                                       <-------

OTTnp + OTTps +
Tpr + Tsr +                     Reply
OTTsp + TpR                     <-------

OTTnp + OTTps +
Tpr + Tsr +                     Delayed ACK
OTTsp + TdA                     ------->

OTTnp + OTTps +
OTTsp + OTTpn +
Tpr + Tsr +      Delayed ACK
TpR + TdA        ------->

Key
---
OTT   = One-way Trip Time
OTTnp = One-way trip time (NAS to Relay/Proxy)
OTTpn = One-way trip time (Relay/Proxy to NAS)
OTTps = One-way trip time (Relay/Proxy to Server)
OTTsp = One-way trip time (Server to Relay/Proxy)
TdA   = Delayed ACK timer
Tpr   = Relay/Proxy request processing time
TpR   = Relay/Proxy reply processing time
Tsr   = Server request processing time

At time 0, the NAS sends its request to the relay/proxy. Ignoring serialization time, the request reaches the relay/proxy at time OTTnp, and then the relay/proxy spends an extra Tpr forwarding it toward the home server. TdA after getting the request, the relay/proxy sends a delayed ACK. That delayed ACK goes out on its own, instead of riding along with the reply, as long as TdA < OTTps + OTTsp + Tpr + Tsr + TpR ๐ŸŽ€.

Typically Tpr < TdA, which means the delayed ACK gets sent after the relay/proxy forwards the request to the server but before the reply comes back from the server. Still, depending on the TCP implementation on the relay/proxy and when the request shows up, the delayed ACK can also be sent before the request gets forwarded ๐Ÿงš.

At time OTTnp + OTTps + Tpr, the server gets the request, and Tsr later it generates the reply. Where Tsr < TdA, the reply will carry a piggybacked ACK. However, depending on how responsive the server is and on its TCP implementation, the ACK and reply might be sent separately. That can happen, for example, when a slow database or storage system has to be accessed before the reply can go out ๐Ÿ’€.

At time OTTnp + OTTps + OTTsp + Tpr + Tsr, the reply/ACK reaches the relay/proxy, which then takes TpR extra to forward the reply to the NAS. TdA after receiving the reply, the relay/proxy generates a delayed ACK. Typically TpR < TdA, so the delayed ACK goes to the server after the relay/proxy has already forwarded the reply to the NAS. But depending on the circumstances and the relay/proxy's TCP implementation, the delayed ACK might go out first ๐ŸŒˆ.

Just like a delayed ACK sent in response to a request, which can be piggybacked if the reply comes back fast enough, an ACK sent in response to a reply from the server can only be piggybacked if more request traffic is available. Because the inter-packet spacing in typical AAA scenarios is so high, this is unlikely unless the AAA protocol supports a reply ACK ๐Ÿ˜ค.

At time OTTnp + OTTps + OTTsp + OTTpn + Tpr + Tsr + TpR, the NAS receives the reply. TdA later, a delayed ACK is generated โœจ.

B.2 Re-directs ๐Ÿฆ‹

Re-directs work by referring a NAS to the AAA server, so the NAS can talk to the AAA server directly ๐Ÿ’–. Since a direct transport connection gets set up, the end-to-end connection will self-clock. Iconic ๐Ÿ‘‘.

With re-directs, delayed ACKs happen less often than with application-layer proxies, because the Re-direct and the Server will typically piggyback replies with ACKs ๐Ÿซถ.

Here's how the sequence of events goes:

Time            NAS             Re-direct       Server
------          ---             ---------       ------

0               Request
                ------->
OTTnp + Tpr                     Redirect/ACK
                                <-------

OTTnp + Tpr +   Request
OTTpn + Tnr     ------->

OTTnp + OTTpn +
Tpr + Tsr +                                     Reply/ACK
OTTns                                           <-------

OTTnp + OTTpn +
OTTns + OTTsn +
Tpr + Tsr +      Delayed ACK
TdA              ------->

Key
---
OTT   = One-way Trip Time
OTTnp = One-way trip time (NAS to Re-direct)
OTTpn = One-way trip time (Re-direct to NAS)
OTTns = One-way trip time (NAS to Server)
OTTsn = One-way trip time (Server to NAS)
TdA   = Delayed ACK timer
Tpr   = Re-direct processing time
Tnr   = NAS re-direct processing time
Tsr   = Server request processing time

B.3 Store and Forward Proxies ๐Ÿ“

With a store and forward proxy, the proxy can send a reply to the NAS before it has forwarded the request to the server ๐Ÿ™ƒ. Store and forward proxies are mostly deployed for accounting [RFC2975], but they can also be used to enforce authentication/authorization policy, as described in [RFC2607].

Here's the catch, though. As [RFC2975] points out, store and forward proxies can hurt accounting reliability ๐Ÿ˜ฌ. When the proxy replies to the NAS without hearing back from the accounting server, the NAS gets tricked into thinking its accounting request was accepted by the accounting server, even though it wasn't. So the NAS can delete the accounting packet from non-volatile storage before the accounting server has accepted it. That leaves the proxy on the hook for delivering accounting packets. If the proxy has moving parts (like a disk drive) and the NAS doesn't, overall system reliability can go down. That's why store and forward proxies SHOULD NOT be used ๐Ÿšซ.

Here's how the sequence of events goes:

Time            NAS             Proxy           Server
------          ---             -----           ------

0               Request
                ------->
OTTnp + TpR                     Reply/ACK
                                <-------

OTTnp + Tpr                     Request
                                ------->

OTTnp + OTTph +                                 Reply/ACK
Tpr + Tsr                                       <-------

OTTnp + OTTph +
Tpr + Tsr +                     Reply
OTThp + TpR                     <-------

OTTnp + OTTph +
Tpr + Tsr +                     Delayed ACK
OTThp + TdA                     ------->

OTTnp + OTTph +
OTThp + OTTpn +
Tpr + Tsr +      Delayed ACK
TpR + TdA        ------->

Key
---
OTT   = One-way Trip Time
OTTnp = One-way trip time (NAS to Proxy)
OTTpn = One-way trip time (Proxy to NAS)
OTTph = One-way trip time (Proxy to Home server)
OTThp = One-way trip time (Home Server to Proxy)
TdA   = Delayed ACK timer
Tpr   = Proxy request processing time
TpR   = Proxy reply processing time
Tsr   = Server request processing time

B.4 Transport Layer Proxies ๐Ÿงšโ€โ™€๏ธ

Beyond acting as proxies at the application layer, transport layer proxies also forward transport ACKs between the AAA client and the server ๐Ÿ’œ. This splices the client-proxy and proxy-server connections together into one connection that acts as if it runs end-to-end, and that means it self-clocks ๐Ÿ”ฅ. Since transport proxies work at the transport layer, they can't be implemented purely as applications, and honestly they're rarely deployed ๐Ÿฅบ.

With a transport proxy, the sequence of events goes like this:

Time            NAS             Proxy           Home Server
------          ---             -----           -----------

0               Request
                ------->
OTTnp + Tpr                     Request
                                ------->

OTTnp + OTTph +                                 Reply/ACK
Tpr + Tsr                                       <-------

OTTnp + OTTph +
Tpr + Tsr +                     Reply/ACK
OTThp + TpR                     <-------

OTTnp + OTTph +
OTThp + OTTpn +
Tpr + Tsr +      Delayed ACK
TpR + TdA        ------->


OTTnp + OTTph +
OTThp + OTTpn +
Tpr + Tsr +                     Delayed ACK
TpR + TpD                       ------->

Key
---
OTT   = One-way Trip Time
OTTnp = One-way trip time (NAS to Proxy)
OTTpn = One-way trip time (Proxy to NAS)
OTTph = One-way trip time (Proxy to Home server)
OTThp = One-way trip time (Home Server to Proxy)
TdA   = Delayed ACK timer
Tpr   = Proxy request processing time
TpR   = Proxy reply processing time
Tsr   = Server request processing time
TpD   = Proxy delayed ack processing time

Intellectual Property Statement โœจ

Quick legal-ish vibe check, babe ๐Ÿ“œ. The IETF doesn't take a position on whether any intellectual property or other rights that someone might claim over the technology in this document are valid or how far they reach, and it also doesn't say whether any license under those rights is or isn't available. It hasn't made any effort to hunt those rights down either. If you want the IETF's rules on rights for standards-track and standards-related documents, check out BCP-11 ๐ŸŽ€. Copies of any claims of rights that were made available for publication, plus any assurances of licenses that will be offered, or the outcome of any attempt to get a general license or permission for implementers or users to use those proprietary rights, can all be requested from the IETF Secretariat ๐Ÿ’….

The IETF also invites anyone to tell it about any copyrights, patents, patent applications, or other proprietary rights that might cover technology needed to practice this standard. Send that info to the IETF Executive Director ๐Ÿซถ.

Acknowledgments ๐ŸŒธ

Huge thanks to Allison Mankin of AT&T, Barney Wolff of Databus, Steve Rich of Cisco, Randy Bush of AT&T, Bo Landarv of IP Unplugged, Jari Arkko of Ericsson, and Pat Calhoun of Blackstorm Networks ๐Ÿ’–. They all had some fruitful discussions about AAA transport, and this doc is better because of them ๐Ÿ‘‘.

Authors' Addresses ๐Ÿฆ‹

Bernard Aboba
Microsoft Corporation
One Microsoft Way
Redmond, WA 98052

Phone: +1 425 706 6605
Fax:   +1 425 936 7329
EMail: bernarda@microsoft.com


Jonathan Wood
Sun Microsystems, Inc.
901 San Antonio Road
Palo Alto, CA 94303

EMail: jonwood@speakeasy.net

Copyright (C) The Internet Society (2003). All Rights Reserved. ๐Ÿ’– Okay, legal stuff, but it matters, bestie.

Anyone can copy and share this document, and translations are welcome too. You can even write derivative works that comment on it, explain it, or help people implement it, and publish and distribute those in whole or in part with no restrictions at all ๐Ÿฆ‹. The only rule is that the copyright notice and this paragraph have to stay on every copy and every derivative work.

The document itself is off-limits for edits, though ๐Ÿ™…โ€โ™€๏ธ You can't remove the copyright notice or the references to the Internet Society or other Internet organizations. There are two exceptions. One is developing Internet standards, where the copyright procedures in the Internet Standards process have to be followed. The other is translating it into languages other than English.

These permissions are perpetual, so the Internet Society and its successors or assigns can't take them back ๐ŸŒˆ

The document and the information in it are provided "AS IS" ๐Ÿ˜ญ THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement ๐ŸŽ€

Funding for the RFC Editor function is currently provided by the Internet Society. ๐Ÿซถ Thank you to them for keeping the RFC Editor running, periodt ๐Ÿ‘‘

๐Ÿ“ฆ where this page comes from