//// 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 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 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_^]): ++++ Go Reference

++++ 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 <> 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": * <> * <> Both make use of the <>, 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"] |=== | <> (5 Bytes) | <> |=== [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 <>, it immediately follows the EtherType value. In <>, it immediately follows the IPv4/IPv6 header. In its current form, this is: .AnnNet Prefix [cols="^.^1s,^.^1s,^.^1s,^.^1s,^.^1s"] |=== 4+| <> | | <> | <> | <> | <> | <> |=== [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 <>, and then moving on to the <>, 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 <>, which is the arbitrary/implementation-specific data that follows the <> (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 <>. 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 <> in the <>. It is an arbitrary length (specified/bounded by <>) 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 <> 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 | <> |=== 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 <> (EtherType `0x0800`) and/or <> (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 <> 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 | <> |=== 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 <>)_ VI:I:: Internet Header Length _(4 Bits; see <>)_ DE:D:: DSCP (Differentiated Services Code Point; QoS/traffic class) _(6 Bits; see <>)_ DE:E:: ECN (Explicit Congestion Notification) _(2 Bits; see <>)_ IP:L:: Total size of IP header + payload (not to be confused with <>) _(2 Bytes)_ IP:I:: Identification (used in fragmentation) _(2 Bytes)_ IP:F:: IP Flags _(3 bits; see <>)_ IP:R:: Fragmentation Offset _(13 Bits; see <>)_ IP:T:: TTL _(1 Byte)_ IP:P:: <> _(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 <> 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 | <> |=== 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 <>)_ VTF:T:: Traffic Class _(8 Bits)_ _(*not* 1 Byte; see <>)_ VTF:F:: Flow Label _(20 bits; see <>)_ IP:L:: IP Payload Length (not to be confused with <>) _(2 Bytes)_ IP:N:: <> (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 <> -- 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 <> -- 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[] ---- ====