RFC 2186

Internet Cache Protocol (ICP), version 2

πŸ“… published September 1997, from ietf

RFC 2186: Internet Cache Protocol (ICP), version 2 πŸ¦‹

Okay bestie, this is RFC 2186, and it's called Internet Cache Protocol (ICP), version 2. πŸ’– It was written by D. Wessels and K. Claffy from the National Laboratory for Applied Network Research/UCSD. It's in the Informational category and dated September 1997. Its header doesn't list anything it obsoletes or updates. ✨

Status of This Memo 🌸

This memo provides information for the Internet community. It does not specify an Internet standard of any kind, so it's more of a "here's how this works" doc than a rulebook. Distribution of this memo is unlimited. 🫢

Abstract ✨

So this doc describes version 2 of the Internet Cache Protocol (ICPv2), the version that's actually running in two World-Wide Web proxy cache packages[3,5]. ICP is a lightweight message format that Web caches use to talk to each other. πŸ’… Caches use it to swap hints about whether a URL exists in a neighbor cache. They send ICP queries and replies to figure out the best place to grab an object from. It's giving efficiency. πŸ”₯

This document only covers the format and fields of ICP messages. A companion document (RFC2187) explains how ICP gets applied to Web caches. Lots of independent caching implementations already use ICP now, so the goal here is to write down the existing practical uses. That way people trying to build, deploy, and extend ICP for their own purposes have something solid to work from. 🧚

1. Introduction πŸ’œ

ICP is a message format for talking between Web caches. Web caches use HTTP[1] to move object data around, but caches are happier with a simpler, lighter protocol. πŸ“ ICP is mostly used in a cache mesh to find specific Web objects in neighboring caches. One cache sends an ICP query to its neighbors, and the neighbors send back ICP replies saying either "HIT" or "MISS." πŸŽ€

In current practice, ICP runs on top of UDP, but nothing says it has to stay on UDP. The authors think ICP over UDP has features that matter a lot for Web caching. An ICP query/reply exchange needs to happen fast, usually within a second or two, because a cache can't sit around waiting longer than that before it starts pulling an object. ⏱️ If a reply never shows up, the network path is probably congested or broken. Either way, you wouldn't want to pick that neighbor. 😭 As a quick read on what's going on between neighbor caches right now, ICP over a lightweight protocol like UDP beats doing it with the extra overhead of TCP. ✨

ICP messages can do more than find objects, too. They can help with cache selection. If a cache doesn't reply, that might mean a network or system failure, and the ICP reply can carry info that helps pick the best source for grabbing an object. πŸ‘‘

ICP was first developed by Peter Danzig, et. al. at the University of Southern California as a central part of hierarchical caching in the Harvest research project[3]. Iconic origin story, honestly. 🌈

ICP Message Format πŸŽ€

Every ICP message has a 20-octet fixed header, followed by a variable-sized payload (see Figure 1). πŸ’–

NOTE: All fields must be represented in network byte order. 🫢

     0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     Opcode    |    Version    |         Message Length        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                         Request Number                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                            Options                            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                          Option Data                          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       Sender Host Address                     |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   |                            Payload                            |
   /                                                               /
   /                                                               /
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                     FIGURE 1: ICP message format.

Here's the breakdown of each field, bestie. πŸ“‹

Opcode πŸ¦‹

One of the opcodes defined below.

Version 🌸

This is the ICP protocol version number. Right now, both version two and version three are in use. This document only describes version two. The version field is there so the protocol can grow in the future. 🌱

Message Length πŸ’…

This is the total length, in octets, of the ICP message. ICP messages MUST not exceed 16,384 octets in length. Non-negotiable, no cap. 🚫

Request Number 🧚

This is an opaque identifier. When a cache responds to a query, this value must be copied into the reply message. ✨

Options 🌈

This is a 32-bit field of option flags. It lets this version of the protocol extend itself in certain limited ways. Check out "ICP Option Flags" below. πŸ‘€

Option Data πŸ’œ

This is a four-octet field for optional features. The following ICP features make use of it:

The ICP_FLAG_SRC_RTT option uses the low 16 bits of Option Data to return RTT measurements. The ICP_FLAG_SRC_RTT option is described further below. πŸ“‘

Sender Host Address πŸ“

This is the IPv4 address of the host sending the ICP message. Honestly, this field should probably not be trusted over what you get from getpeername(), accept(), and recvfrom(). There's some ambiguity about why this field originally existed. In practice, it isn't used. πŸ™ˆ

Payload πŸŽ€

What's in the Payload field depends on the Opcode, but most of the time it holds a null-terminated URL string. πŸ”—

2. ICP Opcodes ✨

Okay bestie, here's the opcode lineup πŸ’– Every ICP message starts with an opcode that tells you what kind of message it is. Here's the full list:

Value    Name
-----    -----------------
    0    ICP_OP_INVALID
    1    ICP_OP_QUERY
    2    ICP_OP_HIT
    3    ICP_OP_MISS
    4    ICP_OP_ERR
  5-9    UNUSED
   10    ICP_OP_SECHO
   11    ICP_OP_DECHO
12-20    UNUSED
   21    ICP_OP_MISS_NOFETCH
   22    ICP_OP_DENIED
   23    ICP_OP_HIT_OBJ

ICP_OP_INVALID πŸ™ˆ

This one is a placeholder, basically a safety net for catching zero-filled or malformed messages. A cache MUST never intentionally send an ICP_OP_INVALID message. If something goes wrong, ICP_OP_ERR SHOULD be used instead πŸ’…

ICP_OP_QUERY πŸ”₯

This is the main "hey, do you have this?" message. Heads up, its payload is shaped differently from most of the others. It starts with the requester's IPv4 address, then the URL.

The Requester Host Address is NOT the address of the cache that's sending the ICP message. It's the address of the cache's client that started the request. This field is often zero filled, and an ICP message with an all-zero Requester Host Address SHOULD be read as "requester address not specified." It does not mean the address is a real, valid IPv4 address, so don't go there πŸ™…β€β™€οΈ

ICP_OP_QUERY payload format:

  0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     Requester Host Address                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
/                       Null-Terminated URL                     /
/                                                               /
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

When an ICP_OP_QUERY comes in, the recipient MUST send back one of these: ICP_OP_HIT, ICP_OP_MISS, ICP_OP_ERR, ICP_OP_MISS_NOFETCH, ICP_OP_DENIED, or ICP_OP_HIT_OBJ. No other replies allowed πŸŽ€

ICP_OP_SECHO πŸ¦‹

This one is like a query, but it's for simulating a query to an origin server. If you're using ICP to pick the closest neighbor, you can include the origin server in the mix by bouncing an ICP_OP_SECHO message off its echo port. The payload is just the null-terminated URL.

NOTE: the echo server won't interpret the data at all, so you could send it literally anything. This opcode is what lets you tell apart a real query or response, random garbage, and an echo response 🧚

ICP_OP_DECHO 🌸

Similar energy to ICP_OP_QUERY, but this one simulates a query to a cache that doesn't use ICP. If you're using ICP to choose the closest neighbor, a non-ICP cache can join the party by bouncing an ICP_OP_DECHO message off its echo port. The payload is again just the null-terminated URL.

NOTE: the catch here is that a system's echo port can be working perfectly while the cache software isn't running at all 😭


Now for the replies. ICP_OP_HIT, ICP_OP_MISS, ICP_OP_ERR, ICP_OP_MISS_NOFETCH, ICP_OP_DENIED, and ICP_OP_HIT_OBJ are the six opcodes that get sent in response to an ICP_OP_QUERY. Unless it says otherwise, the payload MUST be the null-terminated URL string. Both the URL string and the Request Number field MUST be exactly the same as what was in the ICP_OP_QUERY πŸ’œ

ICP_OP_HIT πŸ’–

An ICP_OP_HIT means the requested URL is in this cache AND the requester is allowed to grab it. ✨

ICP_OP_MISS πŸ“

An ICP_OP_MISS means the requested URL is not in this cache. The querying cache can still decide to fetch the URL from the replying cache, so it's kind of an open invitation πŸ’…

ICP_OP_ERR πŸ’€

An ICP_OP_ERR means something went wrong while parsing or handling the query, like an invalid URL. Oof 😬

ICP_OP_MISS_NOFETCH 🌈

An ICP_OP_MISS_NOFETCH means "I'm up, but I'm not in the mood for cache misses right now." An example is a startup phase, when a cache might be rebuilding its object store. A cache in that state may wish to return ICP_OP_HIT for hits, but not ICP_OP_MISS for misses. Basically it's saying "I'm alive, but please don't fetch this URL from me right now" 🫢

Note, ICP_OP_MISS_NOFETCH is NOT the same as ICP_OP_MISS! An ICP_OP_MISS is an invitation to fetch the URL from the replying cache (if the relationship allows it). An ICP_OP_MISS_NOFETCH is a request to not fetch the URL from the replying cache. Totally different vibes πŸ™ˆ

ICP_OP_DENIED 🚫

An ICP_OP_DENIED means the querying site isn't allowed to retrieve the named object from this cache. Caches and proxies can have pretty complex access controls, so this reply MUST be read as "you're not allowed to request this particular URL from me at this particular time."

Caches that get a high percentage of ICP_OP_DENIED replies are probably misconfigured. A cache SHOULD keep track of the percentage of all its replies that are ICP_OP_DENIED, and disable any neighbor that goes over a certain threshold (for example, 95% of 100 or more queries).

Similarly, a cache SHOULD track the percentage of ICP_OP_DENIED messages going to a given address. If that percentage goes over a threshold (for example, 95% of 100 or more), the cache MAY choose to ignore all later ICP_OP_QUERY messages from that address until someone steps in administratively πŸ‘‘

ICP_OP_HIT_OBJ ⭐

This is just like an ICP_OP_HIT, except the actual object data is included right in the reply message. Lots of objects are small enough to fit in the query response, which means you can skip the follow-up HTTP request for the object. Efficient!

CAVEAT: ICP_OP_HIT_OBJ has some side effects that make it undesirable. It transfers object data without HTTP, so it skips the normal HTTP processing, including authorization and age validation. It also tends to be much bigger than the path MTU, which causes fragmentation of the UDP packet. For all these reasons, use of ICP_OP_HIT_OBJ is NOT RECOMMENDED 🚨

A cache MUST NOT send an ICP_OP_HIT_OBJ unless the ICP_FLAG_HIT_OBJ flag is set in the query message's Options field.

ICP_OP_HIT_OBJ payload format:

  0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
/                       Null-Terminated URL                     /
/                                                               /
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Object Size          |                                |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
|                                                               |
/                           Object Data                         /
/                                                               /
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

The receiving application MUST check that it actually gets Object Size octets of data. If it doesn't, it SHOULD treat the ICP_OP_HIT_OBJ reply as if it were a normal ICP_OP_HIT 🧐

NOTE: the Object Size field doesn't necessarily start on a 32-bit boundary like the diagram shows. It starts right after the NULL byte of the URL string. Tiny detail, big deal πŸ’…

UNRECOGNIZED OPCODES πŸ€·β€β™€οΈ

ICP messages with unrecognized or unused opcodes SHOULD be ignored, meaning no reply gets generated. The application MAY choose to note the weird behaviour in a log file πŸ“


3. ICP Option Flags ✨

Next up are the option flags, which live in the Options field πŸŽ€

0x80000000 ICP_FLAG_HIT_OBJ πŸ“

This flag is set in an ICP_OP_QUERY to say it's okay to respond with an ICP_OP_HIT_OBJ, but only if the object data fits in the reply.

0x40000000 ICP_FLAG_SRC_RTT 🌸

This flag is set in an ICP_OP_QUERY when the requester would like the ICP reply to include the responder's measured RTT to the origin server.

When a cache gets an ICP_OP_QUERY with ICP_FLAG_SRC_RTT set, it SHOULD check its internal database of RTT measurements. If there's a value, the RTT MUST be expressed as a 16-bit integer, in milliseconds. If there isn't one, the responder can either set the RTT value to zero, or clear the ICP_FLAG_SRC_RTT bit in the ICP reply. The ICP reply MUST not be delayed while waiting for an RTT measurement to happen. No waiting around, bestie ⏰

This flag is also set in an ICP reply (ICP_OP_HIT, ICP_OP_MISS, ICP_OP_MISS_NOFETCH, or ICP_OP_HIT_OBJ) to show that the low 16 bits of the Option Data field contain the measured RTT to the host given in the requested URL. If ICP_FLAG_SRC_RTT is clear in the query, then it MUST also be clear in the reply. If ICP_FLAG_SRC_RTT is set in the query, it MAY or MAY NOT be set in the reply. Flexible! πŸ¦‹


4. Security Considerations πŸ”

The security issues relating to ICP are discussed in the companion document, RFC2187. Go read it, because security is not a vibe you want to skip πŸ’€


5. References πŸ“š

[1] Fielding, R., et. al, "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2068, UC Irvine, January 1997.

[2] Berners-Lee, T., Masinter, L., and M. McCahill, "Uniform Resource Locators (URL)", RFC 1738, CERN, Xerox PARC, University of Minnesota, December 1994.

[3] Bowman M., Danzig P., Hardy D., Manber U., Schwartz M., and Wessels D., "The Harvest Information Discovery and Access System", Internet Research Task Force - Resource Discovery, http://harvest.transarc.com/.

[4] Wessels D., Claffy K., "ICP and the Squid Web Cache", National Laboratory for Applied Network Research, http://www.nlanr.net/~wessels/Papers/icp-squid.ps.gz

[5] Wessels D., "The Squid Internet Object Cache", National Laboratory for Applied Network Research, http://squid.nlanr.net/Squid/


6. Acknowledgments 🫢

The authors wish to thank Paul A Vixie <paul@vix.com> for giving excellent feedback on this document. Iconic behaviour from Paul πŸ‘‘


7. Authors' Addresses πŸ–‹οΈ

Duane Wessels National Laboratory for Applied Network Research 10100 Hopkins Drive La Jolla, CA 92093

EMail: wessels@nlanr.net

K. Claffy National Laboratory for Applied Network Research 10100 Hopkins Drive La Jolla, CA 92093

EMail: kc@nlanr.net

πŸ“¦ where this page comes from