RFC 826

An Ethernet Address Resolution Protocol: Or Converting Network Protocol Addresses to 48.bit Ethernet Address for Transmission on Ethernet Hardware

πŸ“… published November 1982, from ietf

RFC 826 πŸ’– An Ethernet Address Resolution Protocol

Okay bestie, this is the RFC that taught Ethernet how to find people! πŸ¦‹ It's from the Network Working Group and was written by David C. Plummer (DCP@MIT-MC) in November 1982. The full title is An Ethernet Address Resolution Protocol -- or -- Converting Network Protocol Addresses to 48.bit Ethernet Address for Transmission on Ethernet Hardware. It doesn't have a category line, and it doesn't say it obsoletes or updates anything. The bracketed note near the top says it is not the spec of an Internet Standard, just a method put out for comment. 🌸

Abstract ✨

So the setup is this: a host S is running protocol P, and its routing decides it wants to send to a target host T somewhere on a connected piece of 10Mbit Ethernet cable. πŸ”Œ To actually send the Ethernet packet, a 48.bit Ethernet address has to be generated. Addresses in protocol P aren't always compatible with Ethernet addresses, since they can be different lengths or different values. 😭 This RFC presents a protocol that lets information get passed around dynamically, so you can build the tables that translate an address A in protocol P's address space into a 48.bit Ethernet address. It's giving problem solver. πŸ’…

Generalizations have been made so the protocol can be used on non-10Mbit Ethernet hardware. Some packet radio networks are examples of that hardware. πŸ“‘


The protocol in here came out of a lot of discussion with several other people, most notably J. Noel Chiappa, Yogen Dalal, and James E. Kulp, plus helpful comments from David Moon. 🫢

[The purpose of this RFC is to present a method of Converting Protocol Addresses (e.g., IP addresses) to Local Network Addresses (e.g., Ethernet addresses). This is a issue of general concern in the ARPA Internet community at this time. The method proposed here is presented for your consideration and comment. This is not the specification of a Internet Standard.]

Notes: πŸ“

This protocol was originally designed for the DEC/Intel/Xerox 10Mbit Ethernet. It has since been generalized so it can be used on other types of networks. Most of the discussion focuses on the 10Mbit Ethernet, and the generalizations come after the Ethernet-specific stuff. 🧚

DOD Internet Protocol will be referred to as Internet. 🌐

Numbers here are in the Ethernet standard, which is high byte first. That's the opposite of how byte addressing works on machines like PDP-11s and VAXes. πŸ™ˆ So you need to take special care with the opcode field (ar$op) described below. Bestie, don't skip this one!!

An agreed upon authority is needed to manage hardware name space values (see below). Until an official authority exists, requests should be submitted to:

David C. Plummer
Symbolics, Inc.
243 Vassar Street
Cambridge, Massachusetts  02139

You can also send network mail to DCP@MIT-MC. πŸ’Œ

The Problem: 🌿

The world is a jungle, and networking adds a whole zoo of animals. 🦁 At nearly every layer of a network architecture, there are several potential protocols that could be used. At a high level, for example, there's TELNET and SUPDUP for remote login. Somewhere below that is a reliable byte stream protocol, which might be CHAOS protocol, DOD TCP, Xerox BSP or DECnet. Even closer to the hardware is the logical transport layer, which might be CHAOS, DOD Internet, Xerox PUP, or DECnet. ✨

The 10Mbit Ethernet lets all of these protocols (and more) coexist on a single cable, using a type field in the Ethernet packet header. πŸŽ€ However, the 10Mbit Ethernet requires 48.bit addresses on the physical cable, and most protocol addresses aren't 48.bits long. They also don't necessarily have any relationship to the 48.bit Ethernet address of the hardware. For example, CHAOS addresses are 16.bits, DOD Internet addresses are 32.bits, and Xerox PUP addresses are 8.bits. πŸ˜΅β€πŸ’« So a protocol is needed to dynamically distribute the correspondences between a <protocol, address> pair and a 48.bit Ethernet address. That's the whole mission! 🎯

Motivation: πŸš€

Use of the 10Mbit Ethernet is growing as more manufacturers ship interfaces that conform to the specification published by DEC, Intel and Xerox. As those interfaces get easier to find, more and more software is being written for them. There are two options: (1) every implementor invents their own method to do some form of address resolution, or (2) every implementor uses a standard so their code can be distributed to other systems without modification. This proposal is trying to set that standard. πŸ‘‘

Definitions: πŸ“š

These are the names for the values that go in the TYPE field of the Ethernet packet header:

    ether_type$XEROX_PUP,
    ether_type$DOD_INTERNET,
    ether_type$CHAOS,
and a new one:
    ether_type$ADDRESS_RESOLUTION.
Also define the following values (to be discussed later):
    ares_op$REQUEST (= 1, high byte transmitted first) and
    ares_op$REPLY   (= 2),
and
    ares_hrd$Ethernet (= 1).

Packet format: πŸŽ€

To communicate mappings from <protocol, address> pairs to 48.bit Ethernet addresses, you need a packet format that carries the Address Resolution protocol. Here's the format of the packet:

    Ethernet transmission layer (not necessarily accessible to
     the user):
    48.bit: Ethernet address of destination
    48.bit: Ethernet address of sender
    16.bit: Protocol type = ether_type$ADDRESS_RESOLUTION
    Ethernet packet data:
    16.bit: (ar$hrd) Hardware address space (e.g., Ethernet,
             Packet Radio Net.)
    16.bit: (ar$pro) Protocol address space.  For Ethernet
             hardware, this is from the set of type
             fields ether_typ$<protocol>.
     8.bit: (ar$hln) byte length of each hardware address
     8.bit: (ar$pln) byte length of each protocol address
    16.bit: (ar$op)  opcode (ares_op$REQUEST | ares_op$REPLY)
    nbytes: (ar$sha) Hardware address of sender of this
             packet, n from the ar$hln field.
    mbytes: (ar$spa) Protocol address of sender of this
             packet, m from the ar$pln field.
    nbytes: (ar$tha) Hardware address of target of this
             packet (if known).
    mbytes: (ar$tpa) Protocol address of target.

Packet Generation: 🌟

As a packet goes down through the network layers, routing works out the protocol address of the next hop and which piece of hardware should have the station with that immediate target protocol address. On the 10Mbit Ethernet, address resolution is needed, so some lower layer (probably the hardware driver) has to consult the Address Resolution module (maybe implemented in the Ethernet support module) to convert the <protocol type, target protocol address> pair into a 48.bit Ethernet address. πŸ”

The Address Resolution module tries to find the pair in a table. If it finds it, it hands the matching 48.bit Ethernet address back to the caller (the hardware driver), which then transmits the packet. βœ… If it doesn't find it, it probably tells the caller it's throwing the packet away (on the assumption that a higher network layer will retransmit it). Then it generates an Ethernet packet with a type field of ether_type$ADDRESS_RESOLUTION.

The Address Resolution module sets the ar$hrd field to ares_hrd$Ethernet, ar$pro to the protocol type being resolved, ar$hln to 6 (the number of bytes in a 48.bit Ethernet address), and ar$pln to the length of an address in that protocol. It sets ar$op to ares_op$REQUEST, ar$sha to its own 48.bit Ethernet address, ar$spa to its own protocol address, and ar$tpa to the protocol address of the machine that's trying to be accessed. 🫧 It doesn't set ar$tha to anything in particular, because that's the value it's trying to figure out. It could set ar$tha to the broadcast address for the hardware (all ones in the case of the 10Mbit Ethernet) if that's convenient for some part of the implementation. Finally, it broadcasts this packet to all stations on the Ethernet cable that the routing mechanism originally picked. πŸ“’

Packet Reception: πŸ’Œ

When an address resolution packet comes in, the receiving Ethernet module hands it to the Address Resolution module. That module follows an algorithm similar to the one below. Negative conditionals mean the end of processing, and the packet gets discarded. πŸ—‘οΈ

?Do I have the hardware type in ar$hrd?
Yes: (almost definitely)
  [optionally check the hardware length ar$hln]
  ?Do I speak the protocol in ar$pro?
  Yes:
    [optionally check the protocol length ar$pln]
    Merge_flag := false
    If the pair <protocol type, sender protocol address> is
        already in my translation table, update the sender
    hardware address field of the entry with the new
    information in the packet and set Merge_flag to true.
    ?Am I the target protocol address?
    Yes:
      If Merge_flag is false, add the triplet <protocol type,
          sender protocol address, sender hardware address> to
      the translation table.
      ?Is the opcode ares_op$REQUEST?  (NOW look at the opcode!!)
      Yes:
    Swap hardware and protocol fields, putting the local
        hardware and protocol addresses in the sender fields.
    Set the ar$op field to ares_op$REPLY
    Send the packet to the (new) target hardware address on
        the same hardware on which the request was received.

Notice that the <protocol type, sender protocol address, sender hardware address> triplet gets merged into the table before the opcode is checked. 🧠 That's because the protocol assumes communication is bidirectional: if A has a reason to talk to B, then B will probably have a reason to talk to A. Also, if an entry already exists for the <protocol type, sender protocol address> pair, the new hardware address supersedes the old one. The "Why is it done this way??" section below gives some motivation for this.

Generalization: 🌈

The ar$hrd and ar$hln fields let this protocol and packet format work on non-10Mbit Ethernets too. For the 10Mbit Ethernet, <ar$hrd, ar$hln> takes the value <1, 6>. For other hardware networks, the ar$pro field may no longer correspond to the Ethernet type field, but it should be associated with the protocol whose address resolution is being sought. πŸ¦‹

Why is it done this way?? πŸ€”

Periodic broadcasting is definitely not desired. πŸ™…β€β™€οΈ Imagine 100 workstations on a single Ethernet, each broadcasting address resolution information once every 10 minutes (that's just one possible set of parameters). That's one packet every 6 seconds. It sounds almost reasonable, but what's the point? The workstations aren't generally going to talk to each other (so they'd have 100 useless entries in a table). They'll mostly be talking to a mainframe, file server or bridge, plus a small number of other workstations for interactive conversations. The protocol described here distributes information only as it's needed, and only once (probably) per boot of a machine. πŸ’–

This format doesn't allow more than one resolution in the same packet. That's for simplicity. If things were multiplexed, the packet format would be a lot harder to digest, and much of the information could be gratuitous. Think of a bridge that talks four protocols, telling a workstation all four protocol addresses when three of them the workstation will probably never use. πŸ™ƒ

This format also lets the packet buffer be reused if a reply is generated. A reply has the same length as a request, and several of the fields are the same. ♻️

The value of the hardware field (ar$hrd) comes from a list kept for this purpose. Right now the only defined value is for the 10Mbit Ethernet (ares_hrd$Ethernet = 1). There's been talk of using this protocol for Packet Radio Networks as well, and that will need another value, as will any future hardware mediums that want to use this protocol. πŸ“‘βœ¨

For the 10Mbit Ethernet, the value in the protocol field (ar$pro)

is taken from the set ether_type$. This is a natural reuse of the assigned protocol types πŸŽ€ Combining it with the opcode (ar$op) would effectively halve the number of protocols that can be resolved under this protocol, and would make a monitor/debugger way more complicated (see Network Monitoring and Debugging below) 😭 It is hoped that we will never see 32768 protocols, but Murphy made some laws which don't let us assume that πŸ’€

In theory, the length fields (ar$hln and ar$pln) are redundant πŸ¦‹ The length of a protocol address should be determined by the hardware type (found in ar$hrd) and the protocol type (found in ar$pro). They're still included for optional consistency checking, and for network monitoring and debugging (see below) ✨

The opcode (ar$op) tells you whether this is a request (which may cause a reply) or a reply to a previous request. 16 bits for this is overkill, but a flag (field) is needed 🌸

The sender hardware address (ar$sha) and sender protocol address (ar$spa) are absolutely necessary 🫢 These are the fields that get put in a translation table, so they're the main event πŸ‘‘

The target protocol address (ar$tpa) is necessary in the request form of the packet, so a machine can figure out whether to enter the sender information in a table or to send a reply 🧚 It's not necessarily needed in the reply form, if you assume a reply is only ever provoked by a request. It's included anyway for completeness, network monitoring, and to simplify the suggested processing algorithm described above (which doesn't look at the opcode until AFTER putting the sender information in a table) πŸ’…

The target hardware address (ar$tha) is included for completeness and network monitoring πŸ“ It has no meaning in the request form, since it's the number the machine is requesting. In the reply form, its meaning is the address of the machine making the request. In some implementations (which don't get to look at the 14.byte ethernet header, for example), this may save some register shuffling or stack space by sending this field to the hardware driver as the hardware destination address of the packet πŸ™ˆ

There are no padding bytes between addresses 🌈 The packet data should be viewed as a byte stream in which only 3 byte pairs are defined to be words (ar$hrd, ar$pro and ar$op), which are sent most significant byte first (Ethernet/PDP-10 byte style) ✨


Network monitoring and debugging

The Address Resolution protocol above lets a machine learn about the higher level protocol activity (e.g., CHAOS, Internet, PUP, DECnet) on an Ethernet cable πŸ‘€ It can figure out which Ethernet protocol type fields are in use (by value) and the protocol addresses within each protocol type. Honestly, the monitor doesn't even need to speak any of the higher level protocols involved πŸ”₯ It goes something like this:

When a monitor receives an Address Resolution packet, it always enters the <protocol type, sender protocol address, sender hardware address> in a table πŸ“ It can work out the length of the hardware and protocol addresses from the ar$hln and ar$pln fields of the packet. If the opcode is a REPLY, the monitor can throw the packet away πŸ—‘οΈ If the opcode is a REQUEST and the target protocol address matches the monitor's own protocol address, the monitor sends a REPLY as it normally would. The monitor only gets one mapping this way, since the REPLY to the REQUEST goes directly to the requesting host πŸ₯Ί The monitor could try sending its own REQUEST, but that could get two monitors into a REQUEST sending loop, so care must be taken ⚠️

Because the protocol and opcode aren't combined into one field, the monitor doesn't need to know which request opcode goes with which reply opcode for the same higher level protocol πŸ’œ The length fields should also give it enough info to "parse" protocol addresses, even though it has no idea what the protocol addresses mean 🧠

A working implementation of the Address Resolution protocol can also be used to debug a non-working implementation πŸ› οΈ Presumably a hardware driver will successfully broadcast a packet with Ethernet type field of ether_type$ADDRESS_RESOLUTION. The format of the packet may not be totally correct, because initial implementations may have bugs, and table management may be slightly tricky πŸ˜… Since requests are broadcast, a monitor will receive the packet and can display it for debugging if it wants πŸ‘‘

An Example

Let there exist machines X and Y that are on the same 10Mbit Ethernet cable 🌸 They have Ethernet address EA(X) and EA(Y), and DOD Internet addresses IPA(X) and IPA(Y). Let the Ethernet type of Internet be ET(IP). Machine X has just been started, and sooner or later it wants to send an Internet packet to machine Y on the same cable πŸ“¦ X knows it wants to send to IPA(Y), and tells the hardware driver (here an Ethernet driver) IPA(Y). The driver consults the Address Resolution module to convert <ET(IP), IPA(Y)> into a 48.bit Ethernet address. But because X was just started, it doesn't have this info yet 😭 So it throws the Internet packet away and instead creates an ADDRESS RESOLUTION packet with:

    (ar$hrd) = ares_hrd$Ethernet
    (ar$pro) = ET(IP)
    (ar$hln) = length(EA(X))
    (ar$pln) = length(IPA(X))
    (ar$op)  = ares_op$REQUEST
    (ar$sha) = EA(X)
    (ar$spa) = IPA(X)
    (ar$tha) = don't care
    (ar$tpa) = IPA(Y)

and broadcasts this packet to everybody on the cable πŸ“’

Machine Y gets this packet, and determines that it understands the hardware type (Ethernet), that it speaks the indicated protocol (Internet), and that the packet is for it ((ar$tpa)=IPA(Y)) 🎯 It enters (probably replacing any existing entry) the information that <ET(IP), IPA(X)> maps to EA(X) πŸ“’ Then it notices it's a request, so it swaps fields, putting EA(Y) in the new sender Ethernet address field (ar$sha), sets the opcode to reply, and sends the packet directly (not broadcast) to EA(X) πŸ’Œ At this point Y knows how to send to X, but X still doesn't know how to send to Y πŸ™ƒ

Machine X gets the reply packet from Y, forms the map from <ET(IP), IPA(Y)> to EA(Y), notices the packet is a reply, and throws it away ✨ The next time X's Internet module tries to send a packet to Y on the Ethernet, the translation will succeed, and the packet will (hopefully) arrive 🀞 If Y's Internet module then wants to talk to X, that will also succeed, since Y has remembered the information from X's request for Address Resolution 🫢

It may be desirable to have table aging and/or timeouts πŸ•°οΈ The implementation of these is outside the scope of this protocol. Here's a more detailed description (thanks to MOON@SCRC@MIT-MC) πŸ¦‹

If a host moves, any connections initiated by that host will work, assuming its own address resolution table is cleared when it moves 🚚 However, connections initiated to it by other hosts won't have any particular reason to know to discard their old address 😬 Still, 48.bit Ethernet addresses are supposed to be unique and fixed for all time, so they shouldn't change. A host could "move" if a host name (and address in some other protocol) were reassigned to a different physical piece of hardware πŸ”§ Also, as we know from experience, there's always the danger of incorrect routing information accidentally getting transmitted through hardware or software error, and it should not be allowed to persist forever ⚠️ Perhaps failure to initiate a connection should inform the Address Resolution module to delete the information, on the basis that the host isn't reachable, possibly because it's down or the old translation is no longer valid πŸ’€ Or perhaps receiving a packet from a host should reset a timeout in the address resolution entry used for transmitting packets to that host. If no packets are received from a host for a suitable length of time, the address resolution entry is forgotten ⏳ This may cause extra overhead to scan the table for each incoming packet, so perhaps a hash or index can make this faster πŸƒβ€β™€οΈ

The suggested algorithm for receiving address resolution packets tries to cut down the recovery time if a host does move 🌈 Recall that if the <protocol type, sender protocol address> is already in the translation table, then the sender hardware address supersedes the existing entry. Therefore, on a perfect Ethernet where a broadcast REQUEST reaches all stations on the cable, each station will get the new hardware address πŸ₯³

Another alternative is to have a daemon perform the timeouts 🧚 After a suitable time, the daemon considers removing an entry. It first sends (with a small number of retransmissions if needed) an address resolution packet with opcode REQUEST directly to the Ethernet address in the table. If a REPLY isn't seen in a short amount of time, the entry is deleted πŸ—‘οΈ The request is sent directly so as not to bother every station on the Ethernet. Just forgetting entries will likely cause useful information to be forgotten, which then has to be regained 😩

Since hosts don't transmit information about anyone other than themselves, rebooting a host will cause its address mapping table to be up to date ✨ Bad information can't persist forever by being passed around from machine to machine. The only bad information that can exist is in a machine that doesn't know some other machine has changed its 48.bit Ethernet address πŸ™ˆ Perhaps manually resetting (or clearing) the address mapping table will suffice 🧹

This issue clearly needs more thought if it is believed to be important πŸ€” It is caused by any address resolution-like protocol πŸ’–

πŸ“¦ where this page comes from