The last of the five qualities I look for in a good protocol design is generality.
To refresh your memory, the first four qualities are: focus, unity, simplicity, and clarity. A great protocol has a focus of purpose that drives the whole design. All the parts of a good design have a unity that usually requires a minimum number of parts. A great protocol will have a simplicity that is on the other side of complexity, and it will have a clarity of description, both of the specification and of the concepts used.
Here I talk about the last attribute, generality.
Generality has to do with two things: applicability and adaptability. First, a general protocol has to provide more than a specific, narrow function. The original need will of course be narrow, but, with thought, the solution to that narrow need can be designed to cover a larger number of cases, and do so simply.
Resolving a problem.
An example is the Address Resolution Protocol (ARP). (RFC 826) The original need was to map an IP address to an Ethernet address so we can send the IP datagram to the correct host or router. If you want to send a message to an IP host for the first time, you won't know the Ethernet address that goes with that IP address.
ARP bridges the gap between IP and Ethernet addresses. Fill out the the protocol field of the ARP packet and broadcast it on the Ethernet segment. The host with the requested IP hears it, fills out the other fields and sends it back to the requesting host. As a bonus the target now knows the Ethernet address of the requesting host.
But, if you look closely at the protocol, you will see it could bridge the gap between a number of different things. You could pair up any network layer protocol referred to in the "protocol address" space, with any data link layer protocol in the "hardware address" space.
The length of the hardware address and protocol address fields in the ARP message varies in size based on earlier fields in the ARP message. One could invent a totally new data link layer and a brand new networking layer protocol all while using the existing ARP protocol to resolve the requests.
Adapt and survive else perish.
Adaptability marks the second attribute of generality. A good protocol can absorb changes.
All IT is, in way, is a model of how the world works. The world, in turn, changes all the time. This means that information technology has to change as well, and networking protocols are no exception.
Where am I? Who am I?
The DHCP protocol presents a good example of this kind of adaptability. DHCP grew out of a protocol called BOOTP (RFC 951) used to boot diskless workstations. It simply asked the question, "Who am I? Where am I? What should I run?" Combined with the trivial file transfer protocol (TFTP, RFC 1350), BOOTP could boot diskless workstations by asking those questions.
Some of the BOOTP header looks a bit like the ARP header. It assumes IP, but different data link protocols can be specified. So, in this way, it was expandable.
The IP information was pretty basic - client and server IP addresses, and the address of a gateway. There was also a 128 byte field to hold the TFTP path-name for the kernel load.
Trouble started soon thereafter. In the next few years, the IP network got more complex. We switch to using subnets instead of the generic A, B, and C classes of the network addresses. We need to know where the Domain Name Server was, where the printer was, and what the maximum transmission units were. And, for a while, it looked like we would be inventing more and more of these kinds of parameters.
There was a vendor-specific field in the BOOTP message that was used to transform BOOTP into something more expressive. It transformed it into Dynamic Host Configuration Protocol (DHCP).
The vendor field became the "options" field. It began with a magic number so we could tell a DHCP message from an older BOOTP message. Then, in this new variable-length "options" field, we stored what are called tagged value pairs. A byte specified a value for an option, the next byte the number of bytes that would follow containing the option data.
The meaning of the code byte is record in a maze of RFCs, so you have to know which code means what. There's codes for everything mentioned above, and much, much more. But what if you don't know what a code means?
That's not a problem. You have the number of bytes in the option, so just skip it, and go to the next option field. If you don't know what it means, you can't do it anyway.
This is a very key attribute of DHCP. You can add new options at will without breaking the existing systems. The only downside shows up when something insists on some option you can't interpret. PXE booting required some new fields that had to be added to DHCP servers before one could PXE boot.
Here's how not to do it:
Some protocol designers put a version number in the header and think that they have taken care of generality. They couldn't be more wrong. A version number only tells you that you can't talk to the end destination. IPv6 is a case in point. It's Ethernet type is 0x86DD, where the IPv4 was 0x0800. Protocol software would struggle with checking the type and would have unecpected behavior.
AoE left space for diferent functions.
Leaving room in the protocol for new features works better. The ATA-over-Ethernet protocol has a byte that specifies the command type. ATA is one command type. Discovery and claiming are another type. We have a total of five so far. The rest of the message is based on the command being used.
At first we only had two commands: discover/config and disk I/O. We then added fencing, and finally two kinds of reservations. All worked without a hitch. If a target doesn't understand it, it just says so.
So there you have it - the attributes to a great protocol: focus, unity, simplicity, clarity, and generality.
Actually, they are the attributes of any good design.