615 lines
29 KiB
Plaintext
615 lines
29 KiB
Plaintext
////
|
|
AnnNet Specification © 2025 by Brent Saner is licensed under Creative Commons Attribution-ShareAlike 4.0 International. To view a copy of this license, visit https://creativecommons.org/licenses/by-sa/4.0/
|
|
////
|
|
|
|
= AnnNet Specification
|
|
Brent Saner <bts@square-r00t.net>
|
|
Last rendered {localdatetime}
|
|
:doctype: book
|
|
:docinfo: shared
|
|
:data-uri:
|
|
:imagesdir: images
|
|
:sectlinks:
|
|
:sectnums:
|
|
:sectnumlevels: 7
|
|
:toc: preamble
|
|
:toc2: left
|
|
:idprefix:
|
|
:toclevels: 7
|
|
//:toclevels: 4
|
|
:source-highlighter: rouge
|
|
:docinfo: shared
|
|
:allmeta: _meta
|
|
:allrules: _rules
|
|
|
|
[id="license"]
|
|
== License
|
|
|
|
++++
|
|
include::LICENSE.html[]
|
|
++++
|
|
|
|
In a nutshell, this means any may:
|
|
|
|
* Use it in commercial/proprietary/internal works...
|
|
* Expand upon/change the specification...
|
|
** (As long as it is released under the same Creative Commons license)
|
|
|
|
As long as you attribute the original (this document). This can be as simple as something like:
|
|
|
|
====
|
|
Based on AnnNet version <protocol version> as found at https://annnet.io/.
|
|
====
|
|
|
|
More details certainly helps, though; you may want to mention the exact date you "forked" it, etc.
|
|
|
|
Please see the full text as collapsed above or https://creativecommons.org/licenses/by-sa/4.0/legalcode.en[the online version^] of the license for full legal copy.
|
|
|
|
NOTE: In the event of the embedded text in this document differing from the online version, the online version is assumed to take precedence as the valid license applicable to this work.
|
|
|
|
[id="lib"]
|
|
== Reference Library
|
|
The AnnNet Protocol is accompanied by a reference library for Golang, https://pkg.go.dev/r00t2.io/annnet["AnnNet"^] (https://git.r00t2.io/r00t2/go_annnet[_source_^]):
|
|
|
|
++++
|
|
<a href="https://pkg.go.dev/go.pkg.dev/r00t2.io/annnet">
|
|
<img src="https://pkg.go.dev/badge/go.pkg.dev/r00t2.io/annnet.svg"
|
|
alt="Go Reference">
|
|
</a>
|
|
<br />
|
|
<br />
|
|
++++
|
|
|
|
It contains a reference "client" (listener), https://pkg.go.dev/r00t2.io/annnet/annie[`annie`^] (https://git.r00t2.io/r00t2/go_annnet/src/branch/master/cmd/annie[_source_^]), and a reference "server" (announcer), https://pkg.go.dev/r00t2.io/annnet/anna[`anna`^] (https://git.r00t2.io/r00t2/go_annnet/src/branch/master/cmd/annie[_source_^]).
|
|
|
|
Additional reference libraries may be available in the future.
|
|
|
|
[id="disclaimer"]
|
|
== Disclaimer
|
|
|
|
[id="disc_proto"]
|
|
=== The AnnNet Protocol
|
|
This specification is provided as-is with no guarantees or obligations from this specification's author(s).
|
|
|
|
The author(s) is/are not held liable for any damages caused by implementation/use of this protocol.
|
|
|
|
The AnnNet specification is subject to change, but changes are not considered definitive nor effective until/unless tied with/to a specific released version.
|
|
|
|
[id="disc_ref"]
|
|
=== References
|
|
Many outside references are made throughout this document.
|
|
|
|
* The author(s) is/are not sponsored by, contribute to, nor condone any of the resources mentioned unless otherwise specified.
|
|
* The author(s) is/are not sponsored by, nor member(s),contributor(s), or sponsor of, nor condone any organizations or other entities listed or their actions unless otherwise specified.
|
|
|
|
References are suggested as-is with no guarantees or obligations from this specification's author(s).
|
|
|
|
[id="proto"]
|
|
== Protocol
|
|
The AnnNet (pronounced like the woman's name "Annette") protocol is an announcement/query protocol designed for unspecified hosts on a local network. It is a shorthand for __"the **Ann**ouncement **Net**work Protocol"__.
|
|
|
|
AnnNet is designed to operate with or without IP addressing being available, as it can operate on layer 2, layer 3, or both to unknown/unspecified destinations.
|
|
|
|
It is intended as a sort of "announcement" mechanism for sending messages to all hosts on a *locally-linked* (or *single-organization-controlled*) network (such as bootstrapping large-scale layer 3 services/clusters). It was designed with service/implementation-specific host discovery in mind, though other uses are possible.
|
|
|
|
It is recommended that it is only used *sparingly* for *small* messages (such as cluster *bootstrapping* for new members or initial cluster assembly). _Operational_ messages should occur on a well-defined transport layer (e.g. TCP). +
|
|
It is important to avoid the temptation of simply implementing ALL of a service's communication via AnnNet, as this can quite easily overwhelm the physical network's limitations as hosts participating in its communication grows. See the FAQ/FUQ entry <<fq_proto>> for suggestions on how to manage actual service communication instead.
|
|
|
|
[NOTE]
|
|
====
|
|
The https://en.wikipedia.org/wiki/OSI_model[OSI (Open Systems Interconnection) model^] is going to be referenced a fair bit in this document.
|
|
|
|
The linked Wikipedia article is a fantastic primer on it with a plethora of useful links, but if you'd like to read the authoritative material that'd be https://www.iso.org/standard/20269.html[ISO/IEC 7498-1:1994^].
|
|
|
|
ISO/IEC 7498-1:1994 is one of the free-as-in-beer-for-digital-copy ISO/IEC standards available, provided you have an ISO account -- which is also free to create and use. You can use the _Register_ link at the bottom of https://www.iso.org/webstore/login[ISO's Webstore login^] to create a new purchasing account.
|
|
|
|
[[tcpip_guide]]Another fantastic reference for the OSI model (and all things networking) is http://www.tcpipguide.com/[the TCP/IP Guide^] by Charles M. Kozierok. __(I am not sponsored by nor condone the material found in that re)__
|
|
|
|
It is available:
|
|
|
|
* In its entirety for free (-as-in-beer) http://www.tcpipguide.com/free/index.htm[online^] (if you don't mind the large amount of ads)
|
|
** Note that the online version may not map perfectly to the print/PDF versions, and may have different wording.
|
|
** I (Brent) highly recommend supporting the author by either using the donation links at the bottom of that page or purchasing/licensing a donwloaded PDF or print copy, see below.
|
|
* By purchasing a PDF download http://www.tcpipguide.com/la.htm[directly from the author^]
|
|
** Which also allows for http://www.tcpipguide.com/pricing.htm[bulk licensing^] of the e-book for orginaztional use.
|
|
* By purchasing a print and/or PDF copy https://nostarch.com/tcpip.htm[from No Starch Press^]
|
|
** As expected with all other No Starch Press book purchases, a print copy comes with a free digital/e-book copy.
|
|
|
|
I (Brent) have a physical copy from No Starch Press. I find myself referencing the PDF much more often, as it has some very useful document linking within it, but moreso because the print copy is a *behemoth* and is very bulky for anything but a bookshelf and seated-at-a-table reading/research!
|
|
|
|
The OSI model is covered in the *TCP/IP Guide* in _Part I-2_ (chapters *5* to *7* inclusive), starting on _p.79_. +
|
|
If using the online version, _Part I-2_ is summarized/starts http://www.tcpipguide.com/free/t_TheOpenSystemInterconnectionOSIReferenceModel.htm[here^].
|
|
====
|
|
|
|
[id="spec"]
|
|
== Specification
|
|
AnnNet supports two "sub-protocols":
|
|
|
|
* <<spec_link>>
|
|
* <<spec_bcast>>
|
|
|
|
Both make use of the <<spec_msg_pfx>>, though in different places of the frame/packet depending on their implementation. See each sub-protocol below for details.
|
|
|
|
[id="spec_msg"]
|
|
=== AnnNet Message Format
|
|
The general format of an AnnNet message (excluding leading/surrounding/trailing frames, headers, etc.) is:
|
|
|
|
.AnnNet Message
|
|
[cols="^.^1s,^.^2s"]
|
|
|===
|
|
| <<spec_msg_pfx>> (5 Bytes) | <<spec_msg_payload>>
|
|
|===
|
|
|
|
[id="spec_msg_pfx"]
|
|
==== Standard Prefix
|
|
AnnNet defines a specific prefix that must be added before a message. While AnnNet does not dictate the contents of the *payload* in any way, all AnnNet messages must contain this prefix.
|
|
|
|
In <<spec_link>>, it immediately follows the EtherType value.
|
|
|
|
In <<spec_bcast>>, it immediately follows the IPv4/IPv6 header.
|
|
|
|
In its current form, this is:
|
|
|
|
.AnnNet Prefix
|
|
[cols="^.^1s,^.^1s,^.^1s,^.^1s,^.^1s"]
|
|
|===
|
|
4+| <<spec_msg_pfx_ver>> |
|
|
| <<spec_msg_pfx_ver_maj>> | <<spec_msg_pfx_ver_min>> | <<spec_msg_pfx_ver_patch>> | <<spec_msg_pfx_ver_flags>> | <<spec_msg_pfx_len>>
|
|
|===
|
|
|
|
[id="spec_msg_pfx_ver"]
|
|
===== Version
|
|
|
|
[cols="^.^1m,^.^3",options="header"]
|
|
|===
|
|
| Length (Octets/Bytes) | Type
|
|
| 4 | Big-Endian Unsigned 32-Bit Integer/Container
|
|
|===
|
|
|
|
The *Version* field matches the version of AnnNet being used.
|
|
|
|
Because AnnNet follows https://semver.org/[Semantic Versioning^] (v2.0.0) for its specification, this can either be treated as an abstract container (hereafter a "byte-slice version" in this spec) of individual bytes indicating each version sub-field or treated as a whole (hereafter a "single-value version" in this spec).
|
|
|
|
Thus for example, when determing how to parse the following fields from an AnnNet message if incompatible structuring changes are introduced, one can either:
|
|
|
|
* Perform a version comparison sequentially (e.g. via first parsing and comparing the <<spec_msg_pfx_ver_maj>>, and then moving on to the <<spec_msg_pfx_ver_min>>, and so forth) for a byte-slice version
|
|
* Or for a single-value version, a direct integer comparison -- for example, if a single-value *Version* is greater than or equal to `16777216` to check if it is greater than or equal to version `1.0.0` of AnnNet (`16777216` being equal to `0x01`, `0x00`, `0x00`, `0x00`, or more properly `0x01000000`, when big-endian decoded).
|
|
|
|
[TIP]
|
|
====
|
|
Bit-shifting can be used to extract individual version fields from a single-value version.
|
|
|
|
[%collapsible]
|
|
.Example in Go
|
|
=====
|
|
.`examples/extractversion.go`
|
|
[source,go]
|
|
----
|
|
include::examples/extractversion.go[]
|
|
----
|
|
=====
|
|
====
|
|
|
|
[id="spec_msg_pfx_ver_maj"]
|
|
====== Major
|
|
|
|
[cols="^.^1m,^.^3",options="header"]
|
|
|===
|
|
| Length (Octets/Bytes) | Type
|
|
| 1 | Unsigned 8-Bit Integer
|
|
|===
|
|
|
|
The *Major* is the first byte in *Version* (if interpreted as a byte slice and not a big-endian unsigned 32-bit integer).
|
|
|
|
[id="spec_msg_pfx_ver_min"]
|
|
====== Minor
|
|
|
|
[cols="^.^1m,^.^3",options="header"]
|
|
|===
|
|
| Length (Octets/Bytes) | Type
|
|
| 1 | Unsigned 8-Bit Integer
|
|
|===
|
|
|
|
The *Minor* is the second byte in *Version* (if interpreted as a byte slice and not a big-endian unsigned 32-bit integer).
|
|
|
|
[id="spec_msg_pfx_ver_patch"]
|
|
====== Patch
|
|
|
|
[cols="^.^1m,^.^3",options="header"]
|
|
|===
|
|
| Length (Octets/Bytes) | Type
|
|
| 1 | Unsigned 8-Bit Integer
|
|
|===
|
|
|
|
The *Patch* is the third byte in *Version* (if interpreted as a byte slice and not a big-endian unsigned 32-bit integer).
|
|
|
|
[NOTE]
|
|
====
|
|
The "patch" in SemVer may be more accurate to think of it as a "revision" than a "patch", but the term "revision" means something else in Semantic Version specification so "patch" is used here instead.
|
|
====
|
|
|
|
[id="spec_msg_pfx_ver_flags"]
|
|
====== Release Flag(s)
|
|
|
|
[cols="^.^1m,^.^3",options="header"]
|
|
|===
|
|
| Length (Octets/Bytes) | Type
|
|
| 1 | Byte/8-Bit Length Bitmask
|
|
|===
|
|
|
|
The *Release Flag(s)* field is the fourth byte in *Version*. It is not intended as an unsigned 8-bit integer but rather a https://en.wikipedia.org/wiki/Mask_(computing)[bitmasked^] byte.
|
|
|
|
The collection of all flags is coalesced into a single byte on the wire -- an unsigned 8-bit integer -- with each flag occupying a single bit.
|
|
|
|
The following flags are currently defined:
|
|
|
|
.AnnNet Flags
|
|
[cols="^.^1m,.^1m,^.^2",options="header"]
|
|
|===
|
|
| Integer ^.^| Flag | Name
|
|
|
|
| 0 | ANET_NONE | None; stable release.
|
|
| 1 | ANET_PREREL | Pre-release
|
|
| 2 | ANET_UNSTABLE | Unstable
|
|
| 4 | ANET_EXPERIMENT | Experimental
|
|
|===
|
|
|
|
Additionally, several "shorthand" flags are explicitly defined by the bit-wise ``OR``'d combination of other flags:
|
|
|
|
.AnnNet Combined Flags
|
|
[cols="^.^1m,.^1m,^.^3m,^.^2",options="header"]
|
|
|===
|
|
| Integer ^.^| Flag ^.^| Expression | Name
|
|
|
|
| 3 | ANET_BETA | ANET_PREREL \| ANET_UNSTABLE | Beta release
|
|
| 7 | ANET_ALPHA | ANET_BETA \| ANET_EXPERIMENT | Alpha release
|
|
|===
|
|
|
|
A flag's presence can be checked via a bit-wise `AND` against _flag_ being equal to _flag_.
|
|
|
|
[%collapsible]
|
|
.Example in Go
|
|
=====
|
|
.`hasflag.go`
|
|
[source,go]
|
|
----
|
|
include::examples/hasflag.go[]
|
|
----
|
|
=====
|
|
|
|
[id="spec_msg_pfx_len"]
|
|
===== Payload Length
|
|
|
|
[cols="^.^1m,^.^3",options="header"]
|
|
|===
|
|
| Length (Octets/Bytes) | Type
|
|
| 4 | Big-Endian Unsigned 32-Bit Integer
|
|
|===
|
|
|
|
The *Payload Length* indicates the length of the <<spec_msg_payload>>, which is the arbitrary/implementation-specific data that follows the <<spec_msg_pfx>> (and thus the Payload Length is the last field in the Prefix).
|
|
|
|
It *must* be the length of the entirety of the payload that follows (but *not* including the size of the Prefix).
|
|
|
|
[NOTE]
|
|
====
|
|
`0` is a valid Payload Length, as is an empty <<spec_msg_payload>>. However, if Payload Length is specified as `0` but there *is* Payload data, that data must be considered *invalid* by listening implementations and _should not_ be read/__should be__ discarded (with the exception of *validation, testing, or abuse mitigation purposes*).
|
|
====
|
|
|
|
[id="spec_msg_payload"]
|
|
==== Payload
|
|
The *Payload* is the arbitrary data that follows the <<spec_msg_pfx>> in the <<spec_msg>>.
|
|
|
|
It is an arbitrary length (specified/bounded by <<spec_msg_pfx_len>>) of payload data.
|
|
|
|
[id="spec_link"]
|
|
=== AnnNet Link
|
|
*AnnNet Link* operates on OSI layer 2 as an https://en.wikipedia.org/wiki/EtherType[EtherType^] protocol.
|
|
|
|
[WARNING]
|
|
====
|
|
For obvious reasons, this is not going to play well with other EtherTypes (e.g. VLAN/802.1Q tagging).
|
|
|
|
Future versions of AnnNet may implement VLAN support.
|
|
|
|
If VLAN support is added, it will be done so in a dedicated major release.
|
|
====
|
|
|
|
It _may_ send to either a directed MAC/physical address of a host *or* to the broadcast MAC/PHY__(sical)__ address `ff:ff:ff:ff:ff:ff`.
|
|
Its source _must_ be the MAC/PHYS address of the network interface it is sending from.
|
|
|
|
It *must not* traverse physical network boundaries (can't, really, since it's layer 2).
|
|
|
|
It currently uses the `0x88b5` EtherType by default, as AnnNet is still in experimental stages and this EtherType is https://standards-oui.ieee.org/ethertype/eth.txt[reserved for prototyping^] per IEEE Std 802. (`0x88b6` is another viable option for your implementation, as it too is reserved by IEEE Std 802 for prototyping.) See also https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml#ieee-802-numbers-1[IANA's registration list^].
|
|
|
|
If AnnNet is allocated a dedicated IEEE/IANA-registered EtherType, it will be implemented in a new major version release.
|
|
|
|
The <<spec_msg, AnnNet Message>> follows the EtherType value immediately:
|
|
|
|
.AnnNet Link Packet
|
|
[cols="^.^1s,^.^1s,^.^1s,^.^2s"]
|
|
|===
|
|
3+| Ethernet II Header (14 Bytes) |
|
|
| E:D | E:S | E:T | <<spec_msg, AnnNet Message>>
|
|
|===
|
|
|
|
Where:
|
|
|
|
E:D:: Destination MAC/PHY__(sical)__ Address _(6 Bytes)_
|
|
E:S:: Source MAC/PHY__(sical)__ Address _(6 Bytes)_
|
|
E:T:: EtherType (`0x88b5` or `0x88b6`) _(2 Bytes)_
|
|
|
|
[id="spec_bcast"]
|
|
=== AnnNet Broadcast
|
|
AnnNet Broadcast operates on layer 3, making use of <<spec_bcast_v4>> (EtherType `0x0800`) and/or <<spec_bcast_v6>> (EtherType `0x86dd`).
|
|
|
|
[id="spec_bcast_v4"]
|
|
==== IPv4
|
|
If IPv4, the AnnNet Broadcast sender _may_ send to:
|
|
|
|
* The IPv4 limited broadcast address `255.255.255.255/32` (RFC https://datatracker.ietf.org/doc/html/rfc6890#section-2.2.2[6890 § 2.2.2^], https://datatracker.ietf.org/doc/html/rfc8190#section-2.2[8190 § 2.2^])
|
|
* Or a direct address of a host, IPv4 link-local (also known as __Automatic Private IP Addressing/APIPA__, https://datatracker.ietf.org/doc/html/rfc3927[RFC 3927^]) or not.
|
|
** The target host/network *must* not traverse organization boundary (e.g. *must not* be routed directly across the Internet).
|
|
|
|
If using the `255.255.255.255/32` broadcast address, the source address *must* be a network-reachable address of the interface the message is sending from.
|
|
|
|
If using any other address, the source address *must* be an address reachable by the network/host the message is being sent to.
|
|
|
|
[id="spec_bcast_v4_msg"]
|
|
===== Message Format
|
|
|
|
The <<spec_msg, AnnNet Message>> follows the Options value immediately:
|
|
|
|
.AnnNet Broadcast Packet, IPv4
|
|
[cols="^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^2s"]
|
|
|===
|
|
3+| Ethernet II Header +
|
|
(>= 14 Bytes) 14+| IP Header (20-60 Bytes) |
|
|
3+| 2+| V/IHL +
|
|
(1 Byte) 2+| D/E +
|
|
(1 Byte) | | 2+| Fragmentation +
|
|
(1 Byte) | | | | | | |
|
|
|
|
| E:D | E:S | E:T | VI:V | VI:I | DE:D | DE:E | IP:L | IP:I | IP:F | IP:R | IP:T | IP:P | IP:C | IP:S | IP:D | IP:O | <<spec_msg, AnnNet Message>>
|
|
|===
|
|
|
|
Where:
|
|
|
|
E:D:: Destination MAC/PHY__(sical)__ Address _(6 Bytes)_
|
|
E:S:: Source MAC/PHY__(sical)__ Address _(6 Bytes)_
|
|
E:T:: EtherType (`0x86dd`) _(>= 2 Bytes; may be prefixed with VLAN information etc.)_
|
|
VI:V:: Version _(4 Bits; see <<xtra_bitpacked_vihl,Addendum>>)_
|
|
VI:I:: Internet Header Length _(4 Bits; see <<xtra_bitpacked_vihl,Addendum>>)_
|
|
DE:D:: DSCP (Differentiated Services Code Point; QoS/traffic class) _(6 Bits; see <<xtra_bitpacked_de,Addendum>>)_
|
|
DE:E:: ECN (Explicit Congestion Notification) _(2 Bits; see <<xtra_bitpacked_de,Addendum>>)_
|
|
IP:L:: Total size of IP header + payload (not to be confused with <<spec_msg_pfx_len>>) _(2 Bytes)_
|
|
IP:I:: Identification (used in fragmentation) _(2 Bytes)_
|
|
IP:F:: IP Flags _(3 bits; see <<xtra_bitpacked_frag,Addendum>>)_
|
|
IP:R:: Fragmentation Offset _(13 Bits; see <<xtra_bitpacked_frag,Addendum>>)_
|
|
IP:T:: TTL _(1 Byte)_
|
|
IP:P:: <<spec_bcast_protonum, IP/Transport Protocol Number>> _(1 Byte)_
|
|
IP:C:: Header Checksum (RFC https://datatracker.ietf.org/doc/html/rfc1071[1071^], https://datatracker.ietf.org/doc/html/rfc1071[1141^], https://datatracker.ietf.org/doc/html/rfc1624[1624^]) _(2 Bytes)_
|
|
IP:S:: Source IPv4 Address _(32 Bits/4 Bytes)_
|
|
IP:D:: Destination IPv4 Address _(32 Bits/4 Bytes)_
|
|
IP:O:: Options (Optional) (See the https://www.iana.org/assignments/ip-parameters/ip-parameters.xhtml[IANA Registered IP Parameters^] for details) _(Variable Length)_
|
|
|
|
[id="spec_bcast_v6"]
|
|
==== IPv6
|
|
If IPv6, the AnnNet Broadcast sender _may_ send to:
|
|
|
|
* The multicast addresses (``ff0__x__``) with the following scopes (`scop`) (RFC https://datatracker.ietf.org/doc/html/rfc3513#section-2.7[3513 § 2.7^], https://datatracker.ietf.org/doc/html/rfc4291#section-2.7[4291 § 2.7^], https://datatracker.ietf.org/doc/html/rfc7346#section-2[7346 § 2], see also https://www.iana.org/assignments/ipv6-multicast-addresses/ipv6-multicast-addresses.xhtml[IANA IPv6 Multicast Registry^])
|
|
** *except* as reserved by other IANA/IETF/IESG-recognized protocols (i.e. `OSPFIGP`, `NDP`, et. al.):
|
|
*** Scope `1` (`0x0001`), _Interface-Local_
|
|
*** Scope `2` (`0x0002`), _Link-Local_
|
|
*** Scope `4` (`0x0004`), _Admin-Local_
|
|
*** Scope `5` (`0x0005`), _Site-Local_
|
|
*** Scope `8` (`0x0008`), _Organization-Local_
|
|
** A generally safe address would be `ff02::1` (_All Nodes, Link-Local_) but refer to https://www.iana.org/assignments/ipv6-multicast-addresses/ipv6-multicast-addresses.xhtml[the IANA registry^] to select the most appropriate multicast address(es).
|
|
* Or a direct IPv6 Link-Local Address (LLA) of a host (RFC https://datatracker.ietf.org/doc/html/rfc3513#section-2.5.6[3513 § 2.5.6^], https://datatracker.ietf.org/doc/html/rfc3927[3927^], https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.6[4291 § 2.5.6^], https://datatracker.ietf.org/doc/html/rfc7404[7404^] _(tangentially)_)
|
|
* Or a direct IPv6 Unique Local Address (ULA) of a host (https://datatracker.ietf.org/doc/html/rfc4193[RFC 4193^])
|
|
|
|
If using a multicast address, the source address *must* be a network-reachable address of the interface the message is sending from.
|
|
|
|
If using any other address, the source address *must* be an address reachable by the network/host the message is being sent to.
|
|
|
|
[id="spec_bcast_v6_msg"]
|
|
===== Message Format
|
|
|
|
The <<spec_msg, AnnNet Message>> follows the Destination Address value immediately:
|
|
|
|
.AnnNet Broadcast Packet, IPv6
|
|
[cols="^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^1s,^.^2s"]
|
|
|===
|
|
3+| Ethernet II Header +
|
|
(>= 14 Bytes) 8+| IP Header (40 Bytes) |
|
|
3+| 3+| V/TC/Flow (4 Bytes) 6+|
|
|
|
|
| E:D | E:S | E:T | VTF:V | VTF:T | VTF:F | IP:L | IP:N | IP:H | IP:S | IP:D | <<spec_msg, AnnNet Message>>
|
|
|===
|
|
|
|
Where:
|
|
|
|
E:D:: Destination MAC/PHY__(sical)__ Address _(6 Bytes)_
|
|
E:S:: Source MAC/PHY__(sical)__ Address _(6 Bytes)_
|
|
E:T:: EtherType (`0x86dd`) _(>= 2 Bytes; may be prefixed with VLAN information etc.)_
|
|
VTF:V:: Version _(4 Bits; see <<xtra_bitpacked_vtf,Addendum>>)_
|
|
VTF:T:: Traffic Class _(8 Bits)_ _(*not* 1 Byte; see <<xtra_bitpacked_vtf,Addendum>>)_
|
|
VTF:F:: Flow Label _(20 bits; see <<xtra_bitpacked,Addendum>>)_
|
|
IP:L:: IP Payload Length (not to be confused with <<spec_msg_pfx_len>>) _(2 Bytes)_
|
|
IP:N:: <<spec_bcast_protonum, Next Header>> (transport protocol number) _(1 Byte)_
|
|
IP:H:: Hop Limit _(1 Byte)_
|
|
IP:S:: Source IPv6 Address _(128 Bits/16 Bytes)_
|
|
IP:D:: Destination IPv6 Address _(128 Bits/16 Bytes)_
|
|
|
|
[id="spec_bcast_protonum"]
|
|
==== Internet Protocol Number
|
|
AnnNet currently uses the __IPv4 protocol__/__IPv6 Next Header__ protocol number `253` (`0xfd`) by default, as AnnNet is still in experimental stages and this protocol is https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml[reserved for experimentation^] per IANA. (`254`, `0xfe`, is another viable option for your implementation as it too is reserved by IANA for experimentation.)
|
|
|
|
If AnnNet is allocated a dedicated IANA-registered Protocol/Next Header, it will be implemented in a new major version release.
|
|
|
|
[id="limits"]
|
|
== Limitations
|
|
. AnnNet messages *must* fit into a single frame on the network it is being sent/received on. If message continuation or longer messages are wanted/desired, then it is up to the implementer to add a mechanism for this within their implementation's payload.
|
|
|
|
.. Likewise for checksumming; while most NICs will automatically handle the standard CRC32 https://en.wikipedia.org/wiki/Frame_check_sequence[Frame Check Sequence^] at the end of the entire frame (AnnNet Link is still Ethernet II), if you require checksumming within your application for *payloads* it must be accounted for by your application. If you are using hardware that doesn't automatically append/strip the FCS, your application must also account for that as well.
|
|
|
|
.. For AnnNet Broadcast over IPv4, ensure that you are including the 16-bit https://en.wikipedia.org/wiki/Internet_checksum["Internet checksum"^] of the header (see RFCs https://datatracker.ietf.org/doc/html/rfc1071[1071^], https://datatracker.ietf.org/doc/html/rfc1141[1141^], and https://datatracker.ietf.org/doc/html/rfc1624[1624^]). +
|
|
Most kernels can/will automatically insert this (e.g. on Linux, with `IPPROTO_RAW`/raw sockets with the `IP_HDRINCL` option, see https://man7.org/linux/man-pages/man7/raw.7.html[`raw(7)`^]), but if your implementation doesn't/can't use such a mechanism then you must do so yourself. +
|
|
IPv6 does not require a header checksum.
|
|
|
|
[id="fq"]
|
|
== (F)AQ/FUQ (Anticipated, Frequently Asked/Anticipated/Unasked Questions)
|
|
|
|
[id="fq_tcpip"]
|
|
=== Why do you reference the OSI model instead of the TCP/IP model? It's old/outdated/inaccurate.
|
|
Hold onto your seat.
|
|
|
|
Several reasons:
|
|
|
|
. The OSI model is standardized. There is only a *single*, *canonical*, *authoritative* "OSI model" when it comes to network models.
|
|
+
|
|
References are unambiguous. Boundaries between layers and their definitions are *mostly* clear. (And the ISO/IEC provides supplementals for any ambiguities that arise over the years.)
|
|
+
|
|
As for "the TCP/IP model", https://en.wikipedia.org/wiki/Internet_protocol_suite#Layering_evolution_and_representations_in_the_literature[which one are you referring to^]?
|
|
+
|
|
There's no less than *seven different models* that are referred to as "_**the** TCP/IP model_". (The linked-to article doesn't even mention e.g. the DoD model.) And they're all different in ways enough to make this confusing.
|
|
|
|
. The OSI model is more nuanced and detailed.
|
|
+
|
|
When one is talking about *IP protocols* and *service protocols* in the _same context_, things get very confusing very quickly. One can say "protocol" and it can apply to either ambiguously.
|
|
+
|
|
If instead one says "L2 protocol" or "layer 2 protocol" it's immediately clear that it operates without (IP) addressing, or "L3 protocol"/"layer 3 protocol" and it's immediately clear that a protocol that DOES use (IP) addressing is being referenced.
|
|
|
|
[id="fq_proto"]
|
|
=== Why Shouldn't I Use AnnNet for Regular Traffic?
|
|
On a purely technical level, there's nothing *stopping* you from doing so (aside from MTU windows, so you'd need to find some way of implementing message continuation, ordering, checksumming, etc. -- at that point, just use UDP multicast or something else).
|
|
|
|
But AnnNet is designed to be a lightweight announcement protocol for a _local_ (i.e. within the same subnet/link system) network.
|
|
|
|
It is designed to act like e.g.:
|
|
|
|
* https://datatracker.ietf.org/doc/html/rfc826[_An Ethernet Address Resolution Protocol ..._^] (`ARP`)
|
|
* https://datatracker.ietf.org/doc/html/rfc4861[_Neighbor Discovery for IP version 6 (IPv6)_^] (`ND`)
|
|
* Lease requests for:
|
|
** https://datatracker.ietf.org/doc/html/rfc2131[_Dynamic Host Configuration Protocol_^] (`DHCP`)
|
|
** https://datatracker.ietf.org/doc/html/rfc8415[_Dynamic Host Configuration Protocol for IPv6_ (`DHCPv6`)^]
|
|
|
|
etc., but with (very small amounts of) *arbitrary data* making it "plug-and-play" with >= L3 protocols/services' configuration.
|
|
|
|
It explicitly avoids defining any formation of payloads, message format, or the like -- because it is designed to be entirely agnostic of whatever use case it is implemented for.
|
|
|
|
However, AnnNet *strongly encourages* the use of https://wireproto.io/[WireProto^] for payload packing due to its minimal overhead, its strong hierarchical structuring, and its flexibility.
|
|
|
|
[WARNING]
|
|
====
|
|
Future versions of AnnNet **may _require_** use of WireProto (but WireProto itself is a very loose and flexible format, and would not add much overhead).
|
|
|
|
If this requirement is put in place, it will be in its own major revision.
|
|
====
|
|
|
|
If one needs a much more robust solution for anything *beyond* e.g. announcement messages, https://nats.io/[NATS^] may be useful for actual messaging between *known* members. (AnnNet would then be used in this case to provide a mechanism for _making members known/discovered_ with no explicit configuration.) +
|
|
[NOTE]
|
|
====
|
|
NATS also does not define any sort of payload format in its *encapsulated* payloads; most implementations tend to use https://protobuf.dev/[ProtoBuf/Protocol Buffers^], https://msgpack.org/index.html[MessagePack^], JSON, or the like.
|
|
====
|
|
|
|
[id="xtra"]
|
|
== Addendum/Errata/Administrivia
|
|
|
|
[id="xtra_bitpacked"]
|
|
=== Bitpacked Fields
|
|
Certain fields in IP headers are less than 1 byte or don't align to a clean byte boundary on their own, and therefore generally require bitwise operations to read/encapsulate meaningful values within them.
|
|
|
|
[id="xtra_bitpacked_vihl"]
|
|
==== IP Version, IHL (IPv4)
|
|
The IP version and IHL combined make up a single byte, with four-byte "nibbles" each.
|
|
|
|
[NOTE]
|
|
====
|
|
The IHL is calculated as the number of "32-bit words" in the IP header.
|
|
|
|
In other words, `IHL = (B * 8) / 32` (where `B` is the size of the IP header -- everything from "VI:V" to "IP:O" inclusive in <<spec_bcast_v4_msg>> -- in *bytes*).
|
|
|
|
Or, alternatively, `IHL = b / 32` (where `b` is the size of the IP header -- everything from "VI:V" to "IP:O" inclusive in <<spec_bcast_v4_msg>> -- in *bits*).
|
|
|
|
Since the V/IHL is a fixed size, this does *not* cause a recursion/chicken-egg problem.
|
|
====
|
|
|
|
To *create* the Version/IHL value, the Version (*always* `4` because IPv4) is packed as a big-endian 8-bit unsigned integer, and is then bit-shifted to the left by 4 bits and bitwise-``OR``'d with the IHL (as a big-endian 8-bit unsigned integer bitwise-`AND`-masked to the lower bits via `0x0f`/`15`).
|
|
|
|
To *retrieve* the Version and IHL, the value is bit-shifted to the *right* by 4 bits and cast as an 8-bit unsigned integer (this is the Version, `4`), and the original value is also bitwise-``AND``'d with the lower bits via `0x0f` (`15`) and cast as an unsigned 8-bit integer to get the IHL.
|
|
|
|
[%collapsible]
|
|
.Example in Go
|
|
====
|
|
[source,go]
|
|
----
|
|
include::examples/vihl.go[]
|
|
----
|
|
====
|
|
|
|
[id="xtra_bitpacked_de"]
|
|
==== DSCP, ECN (IPv4)
|
|
The DSCP and ECN fields are combined to make up a single byte with a 6-bit and 2-bit "nibble" each, respectively.
|
|
|
|
[NOTE]
|
|
====
|
|
The actual values for DSCP and ECN are sort of scattered about through several different RFCs.
|
|
|
|
Notable DSCP mentions are:
|
|
|
|
* https://datatracker.ietf.org/doc/html/rfc2474#section-4.2.2.1[RFC 2474 § 4.2.2.1^]
|
|
* https://datatracker.ietf.org/doc/html/rfc2475[RFC 2475^]
|
|
* https://datatracker.ietf.org/doc/html/rfc8837#section-5[RFC 8837 § 5^]
|
|
|
|
Notable ECN mentions are:
|
|
|
|
* https://datatracker.ietf.org/doc/html/rfc3168[RFC 3168^]
|
|
* https://datatracker.ietf.org/doc/html/rfc6040[RFC 6040^]
|
|
* https://datatracker.ietf.org/doc/html/rfc8311[RFC 8311^]
|
|
====
|
|
|
|
[%collapsible]
|
|
.Example in Go
|
|
====
|
|
[source,go]
|
|
----
|
|
include::examples/de.go[]
|
|
----
|
|
====
|
|
|
|
[id="xtra_bitpacked_frag"]
|
|
==== Flags, Fragmentation Offset (IPv4)
|
|
The (Fragmentation) Flags and Fragmentation Offset fields are combined to make up 2 bytes with a 3-bit and 13-bit "nibble"/"word" each, respectively.
|
|
|
|
The Fragmentation Flags and Offset are defined in https://datatracker.ietf.org/doc/html/rfc791#section-3.1[RFC 791 § 3.1^] and part of https://datatracker.ietf.org/doc/html/rfc815[RFC 815^].
|
|
|
|
[%collapsible]
|
|
.Example in Go
|
|
====
|
|
[source,go]
|
|
----
|
|
include::examples/frag.go[]
|
|
----
|
|
====
|
|
|
|
[id="xtra_bitpacked_vtf"]
|
|
==== IP Version, Traffic Class, Flow Label (IPv6)
|
|
IPv6 thankfully only has one bitpacking in the header. Unfortunately, it's a triple-whammy.
|
|
|
|
These are mostly defined in:
|
|
|
|
* https://datatracker.ietf.org/doc/html/rfc8200#section-3[RFC 8200 § 3^] for the header format
|
|
* https://datatracker.ietf.org/doc/html/rfc8200#section-7[RFC 8200 § 7^] for the Traffic Class field
|
|
* https://datatracker.ietf.org/doc/html/rfc8200#section-6[RFC 8200 § 6^] for the Flow Label field
|
|
|
|
The IP Version takes up 4 bits (just as in IPv4, except it will always be `6` this time), the Traffic Class field takes up 8 bits, and Flow Labels takes up 20 bits for a total of 32 bits (4 bytes).
|
|
|
|
[%collapsible]
|
|
.Example in Go
|
|
====
|
|
[source,go]
|
|
----
|
|
include::examples/vtf.go[]
|
|
----
|
|
====
|