RFC 8991
GeneRic Autonomic Signaling Protocol Application Program Interface (GRASP API)
GeneRic Autonomic Signaling Protocol Application Program Interface (GRASP API) π¦
Okay bestie, this is RFC 8991 π It's an Informational doc, dated May 2021, with ISSN 2070-1721. The authors are B. Carpenter (Univ. of Auckland), B. Liu, Ed. (Huawei Technologies), W. Wang, and X. Gong (BUPT University). It doesn't list anything it obsoletes or updates, so it's a fresh little spec standing on its own π
Abstract β¨
This doc is a conceptual outline of an Application Programming Interface (API) for the GeneRic Autonomic Signaling Protocol (GRASP). ASAs need an API like this so they can call the GRASP protocol module and swap Autonomic Network messages with other ASAs. GRASP is built for asynchronous operations, so the API will have to adapt to how different programming languages and operating systems handle asynchronicity π
Status of This Memo
Heads up: this document is not an Internet Standards Track specification. It's published purely for informational purposes π§
It's a product of the Internet Engineering Task Force (IETF), so it represents the consensus of the IETF community. It went through public review and got approved for publication by the Internet Engineering Steering Group (IESG). Not every IESG-approved document is a candidate for any level of Internet Standard, so check Section 2 of RFC 7841 for the details π
For the current status, any errata, and how to give feedback, go to https://www.rfc-editor.org/info/rfc8991.
Copyright Notice
Copyright (c) 2021 IETF Trust and the persons identified as the document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they're in effect on the date of publication. Please read these carefully, because they spell out your rights and restrictions for this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they come without warranty as described in the Simplified BSD License π
Table of Contents πΈ
1. Introduction
2. GRASP API for ASA
2.1. Design Assumptions
2.2. Asynchronous Operations
2.2.1. Alternative Asynchronous Mechanisms
2.2.2. Multiple Negotiation Scenario
2.2.3. Overlapping Sessions and Operations
2.2.4. Session Termination
2.3. API Definition
2.3.1. Overview of Functions
2.3.2. Parameters and Data Structures
2.3.3. Registration
2.3.4. Discovery
2.3.5. Negotiation
2.3.6. Synchronization and Flooding
2.3.7. Invalid Message Function
3. Security Considerations
4. IANA Considerations
5. References
5.1. Normative References
5.2. Informative References
Appendix A. Error Codes
Acknowledgements
Authors' Addresses
1. Introduction π
As defined in [RFC8993], the Autonomic Service Agent (ASA) is the atomic entity of an autonomic function, and it gets instantiated on autonomic nodes. These nodes are members of a secure Autonomic Control Plane (ACP), like the one described by [RFC8994].
When ASAs talk to each other, they should use the GeneRic Autonomic Signaling Protocol (GRASP) [RFC8990]. GRASP leans on the message confidentiality and integrity that the ACP gives it, which means every node in a given Autonomic Network shares the same trust boundary, aka the boundary of the ACP π«Ά Nodes that haven't successfully joined the ACP can't send, receive, or intercept GRASP messages through it, and they can't usurp ACP addresses. An ASA runs on an ACP node, so it gets the node's security properties when it transmits over the ACP: message integrity, message confidentiality, and the fact that unauthorized nodes can't join the ACP. So all ASAs in a given Autonomic Network trust each other's messages. For these reasons, the API defined in this document has no explicit security features π
Here's the big one: GRASP is all about the GRASP objective β¨ It's a data structure encoded, like every GRASP message, in Concise Binary Object Representation (CBOR) [RFC8949]. Its main contents are a name and a value, which get explained at more length in the Terminology section of [RFC8990]. When an objective gets passed from one ASA to another using GRASP, its value is either conveyed in one direction (through synchronization or flooding) or negotiated bilaterally. GRASP and the API treat the semantics of the value as opaque, so they don't interpret it. Every objective must be accurately specified in a dedicated specification, as discussed in "Objective Options" (Section 2.10 of [RFC8990]). That specification will define the syntax and semantics of the value, whether and how it supports a negotiation process, whether it supports a dry-run mode, and any other details needed for interoperability. Using CBOR with Concise Data Definition Language (CDDL) [RFC8610] as the data definition language lets the value move between ASAs no matter which programming languages they're written in. Data storage and consistency during negotiation are the responsibility of the ASAs involved. On top of that, GRASP needs to cache the latest values of objectives it receives by flooding π§
As Figure 1 shows, a GRASP implementation could contain several sub-layers. The bottom layer is the GRASP base protocol module, which is only responsible for sending and receiving GRASP messages and maintaining shared data structures. Above that sits the basic API described in this document. The upper layer holds some extended API functions built on the GRASP basic protocol. For example, [GRASP-DISTRIB] describes one possible extended function π
+--------------+ +--------------+
| ASAs | | ASAs |
+--------------+ +--------------+
| | |
| +------------------+ |
| | GRASP Extended | |
| | Function API | |
| +------------------+ |
| | |
+------------------------------------------+
| Basic GRASP API Library |
+------------------------------------------+
|
IPC or system call
|
+------------------------------------------+
| GRASP Core |
| (functions, data structures, daemon(s)) |
+------------------------------------------+
Figure 1: Software Layout
Multiple ASAs in a single node share the same instance of GRASP, kind of like how multiple applications share one TCP/IP stack. The API hides this from individual ASAs, so it isn't discussed further here π
It's desirable for ASAs to be portable user-space programs that use a system-independent API. In many implementations, the GRASP code therefore gets split between user space and kernel space. In user space, library functions provide the API and talk directly to ASAs. In kernel space, a daemon, or a set of sub-services, provides GRASP core functions that don't depend on specific ASAs, like multicast handling and relaying, plus common data structures, like the discovery cache. The GRASP API library needs to talk to the GRASP core through an interprocess communication (IPC) or a system call mechanism. The details are system-dependent π οΈ
Both the GRASP library and the extended function modules should be available to the ASAs. Since the extended functions are expected to arrive incrementally, though, they'll be the subject of future documents. This document only describes the basic GRASP API π¦
The functions the API provides don't map one-to-one onto GRASP messages. Instead, they offer convenient support for message sequences, such as a discovery request followed by responses from several peers, or a negotiation request followed by various possible responses. This choice was made so ASA programmers can write code based on their application requirements without needing to understand protocol details π
Beyond the autonomic infrastructure components described in [RFC8994] and [RFC8995], a simple autonomic node might contain very few ASAs. Such a node might integrate a GRASP protocol stack directly into its code, so it wouldn't require this API to be installed. But the programmer would need a deeper understanding of the GRASP protocol than they would need to use the API π§
This document gives a conceptual outline of the API. It isn't a formal specification for any particular programming language or operating system, and details are expected to get clarified in individual implementations β¨
2. GRASP API for ASA π
2.1. Design Assumptions
The design assumes that an ASA needs to call a separate GRASP implementation. That implementation handles protocol details (security, sending and listening for GRASP messages, waiting, caching discovery results, negotiation looping, sending and receiving synchronization data, etc.), but it doesn't understand individual GRASP objectives (see Section 2.10 of [RFC8990]). The semantics of objectives are unknown to the GRASP protocol and are handled only by the ASAs. So this is an abstract API for use by ASAs. Individual language bindings should be defined in separate documents πΈ
Different ASAs may use GRASP features differently, by using GRASP for:
- discovery purposes only.
- negotiation but only as an initiator (client).
- negotiation but only as a responder.
- negotiation as an initiator or responder.
- synchronization but only as an initiator (recipient).
- synchronization but only as a responder and/or flooder.
- synchronization as an initiator, responder, and/or flooder.
The API also assumes that one ASA may support multiple objectives. Nothing stops an ASA from supporting some objectives for synchronization and others for negotiation π
The API design assumes that the operating system and programming language provide a mechanism for simultaneous asynchronous operations. This is discussed in detail in Section 2.2 β³
A few items are out of scope in this version, since practical experience is needed before including them:
- Authorization of ASAs is not defined as part of GRASP and is a subject for future study.
- User-supplied explicit locators for an objective are not supported. The GRASP core will supply the locator, using the IP address of the node concerned.
- The rapid mode of GRASP (Section 2.5.4 of [RFC8990]) is not supported π
2.2. Asynchronous Operations β³
okay so GRASP lives on asynchronous operations and wait states π and some of its messages are NOT idempotent, which means sending the same message again might cause repeated state changes in the recipient ASA π. Many ASAs need to handle several concurrent operations at once. For example, an ASA might negotiate one objective with a peer while it's discovering and synchronizing a different objective with someone else π¦. Or an ASA that acts as a resource manager might need to run simultaneous negotiations for one objective with multiple different peers π. An ASA like that will probably need uninterruptible atomic changes to its internal data structures, using a mechanism from the operating system and programming language it's built with π«Ά.
2.2.1. Alternative Asynchronous Mechanisms π§΅
Some ASAs need asynchronous operations, so the GRASP core must support them too π. Depending on the operating system and language, there are a bunch of techniques for parallel operations. Three are considered here: multithreading, an event loop structure using polling, and an event loop structure using callback functions β¨.
- Multithreading: the operating system and language provide the support for asynchronous operations, including creation of new threads, context switching between threads, queues, locks, and implicit wait states π§. API calls can be treated as simple synchronous function calls inside their own thread, even if the function includes wait states, blocking, and queueing. Concurrent operations each run in their own threads. For example, the
discover()call may not return until discovery results have arrived or a timeout has occurred. If the ASA has other work to do, thediscover()call must be in a thread of its own π. - Event loop with polling: blocking calls are not acceptable here π. Therefore, all calls must be non-blocking, and the main loop can support multiple GRASP sessions in parallel by repeatedly polling each one for a change of state. To make this work, the API implementation would provide non-blocking versions of all the functions that otherwise involve blocking and queueing. In these calls, a
'noReply'code is returned by each call instead of blocking, until the event it's waiting for (or a failure) has occurred. So, for example,discover()would return'noReply'instead of waiting until discovery has succeeded or timed out. Thediscover()call would be repeated in every cycle of the main loop until it completes. Effectively, it becomes a polling call π. - It was noted earlier that some GRASP messages are not idempotent. In particular, this applies to each step in a negotiation session -- sending the same message twice might produce unintended side effects π¬. Event loop polling doesn't change this: repeating a call after a
'noReply'does not repeat a message; it simply checks whether a reply has been received πΈ. - Event loop with callbacks: the ASA programmer provides a callback function for each asynchronous operation. It gets called asynchronously when a reply is received or a failure such as a timeout occurs π.
2.2.2. Multiple Negotiation Scenario π
GRASP's design allows the following scenario, and it's giving main character energy π. Picture an ASA "A" that acts as a resource allocator for some objective. An ASA "B" launches a negotiation with "A" to obtain or release a quantity of the resource. While that negotiation is underway, "B" decides to launch a second simultaneous negotiation with "A" for a different quantity of the same resource π. So "A" must conduct two separate negotiation sessions at the same time with the same peer, and it must not mix them up π ββοΈ.
Note that ASAs could be designed to avoid this scenario, meaning they'd be restricted to exactly one negotiation session at a time for a given objective. But that would be a voluntary restriction, not required by the GRASP protocol π. In fact, GRASP assumes that any ASA managing a resource may need to conduct multiple parallel negotiations, possibly with the same peer. Communication patterns can get super complex, with a group of ASAs overlapping negotiations among themselves, as described in [ANIMA-COORD] πΈοΈ. That's why the API design allows for such scenarios β¨.
In the callback model, for the scenario just described, ASAs "A" and "B" will each provide two instances of the callback function, one for each session. For this reason, each ASA must be able to tell the two sessions apart, and the peer's IP address is not sufficient for that π . It's also not safe to rely on transport port numbers for this, since future variants of GRASP might use shared ports rather than a separate port per session π. Hence, the GRASP design includes a Session ID π. So when necessary, a session handle (see the next section) is used in the API to tell simultaneous GRASP sessions apart, so that any number of sessions can proceed asynchronously in parallel π.
2.2.3. Overlapping Sessions and Operations π¦
A GRASP session is a finite sequence of messages (for discovery, synchronization, or negotiation) between two ASAs π§©. On the wire, it's uniquely identified by a pseudorandom Session ID plus the IP address of the session's initiator. More details are in "Session Identifier (Session ID)" (Section 2.7 of [RFC8990]) π.
On the first call in a new GRASP session, the API returns a 'session_handle' handle that uniquely identifies the session within the API, so multiple overlapping sessions can be told apart π. A likely implementation is to form the handle from the underlying GRASP Session ID and IP address. This handle must be used in all subsequent calls for the same session. Also see Section 2.3.2.8 β¨.
An additional mechanism that might make polling implementations more efficient is a general call, say notify(). It would check the status of all outstanding operations for the calling ASA and return the session_handle values for all sessions that have changed state π. That would get rid of the need for repeated calls to the individual functions returning a 'noReply'. This call is not described below, since the details are likely to be implementation specific π€·ββοΈ.
One implication for all GRASP implementations is that the GRASP core must keep state for each GRASP operation in progress, most likely keyed by the GRASP Session ID and the GRASP source address of the session initiator ποΈ. Even in a threaded implementation, the GRASP core needs that state internally. The session_handle parameter just exposes this aspect of the implementation π.
2.2.4. Session Termination πͺ
GRASP sessions can end for lots of reasons π€. A session ends when discovery succeeds or times out, when negotiation succeeds or fails, when a synchronization result is delivered, when the other end fails to respond before a timeout expires, when a loop count expires, or when a network socket error occurs. Note that a timeout at one end of a session might show up as a timeout or a socket error at the other end, since GRASP does not send error messages in this case π« . In all cases, the API returns an appropriate code to the caller, which should then release any reserved resources π§Ή. After failure cases, the GRASP specification recommends an exponential backoff before retrying π.
2.3. API Definition π
2.3.1. Overview of Functions πΊοΈ
The functions provided by the API fall into several groups:
- Registration: these functions let an ASA register itself with the GRASP core, and let a registered ASA register the GRASP objectives it will manipulate π.
- Discovery: this function lets an ASA that needs to initiate negotiation or synchronization of a particular objective discover a peer willing to respond π.
- Negotiation: these functions let an ASA act as an initiator (requester) or responder (listener) for a GRASP negotiation session. After initiation, negotiation is a symmetric process, so most of the functions can be used by either party π€.
- Synchronization: these functions let an ASA act as an initiator (requester) or responder (listener and data source) for a GRASP synchronization session π.
- Flooding: these functions let an ASA send and receive an objective that is flooded to all nodes of the ACP π.
Some example logic flows for a resource management ASA are given in [ASA-GUIDE], which may help you understand the descriptions below π. The next section describes parameters and data structures used in multiple API calls. The following sections describe the various groups of function APIs. Those APIs that do not list asynchronous mechanisms are implicitly synchronous in their behavior β.
2.3.2. Parameters and Data Structures π§
2.3.2.1. Integers π’
In this API, integers are assumed to be 32-bit unsigned integers (uint32_t) unless otherwise indicated π.
2.3.2.2. Errorcode π¨
All functions in the API have an unsigned 'errorcode' integer as their return value (the first return value in languages that allow multiple return values) π. An 'errorcode' of zero indicates success. Any other value indicates failure of some kind. The first three errorcodes have special importance:
1- Declined: used to indicate that the other end has sent a GRASP Negotiation End message (M_END) with a Decline option (O_DECLINE) π ββοΈ.2- No reply: used in non-blocking calls to indicate that the other end has sent no reply so far (see Section 2.2) β³.3- Unspecified error: used when no more specific error codes apply π€·ββοΈ.
Appendix A gives a full list of currently suggested error codes, based on implementation experience π. There is no absolute requirement for all implementations to use the same error codes, but this is highly recommended for portability of applications π«Ά.
2.3.2.3. Timeout β°
Whenever a 'timeout' parameter appears, it's an unsigned integer expressed in milliseconds β±οΈ. If it is zero, the GRASP default timeout (GRASP_DEF_TIMEOUT; see [RFC8990]) applies. The exception is the discover() function, which has a different interpretation of a zero timeout π. If no response is received before the timeout expires, the call fails unless otherwise noted π
.
2.3.2.4. Objective πβ¨
okay so an 'objective' is a data structure with a few components, and bestie, these are the building blocks of the whole thing π
name (UTF-8 string): the objective's name π·οΈ
neg (Boolean flag): True if the objective supports negotiation (default False) π€
synch (Boolean flag): True if the objective supports synchronization (default False) π
dry (Boolean flag): True if the objective supports dry-run negotiation (default False) π§ͺ
Note 1: Only one of 'synch' or 'neg' may be True. π ββοΈ Note 2: 'dry' must not be True unless 'neg' is also True. π« Note 3: In some programming languages, the preferred implementation may be to represent the Boolean flags as bits in a single byte, which is how they are encoded in GRASP messages. In other languages, an enumeration might be preferable. π
loop_count (unsigned integer, uint8_t): limit on negotiation steps, etc. (default GRASP_DEF_LOOPCT; see [RFC8990]). The 'loop_count' is set to a suitable value by the initiator of a negotiation, to prevent indefinite loops. It is also used to limit the propagation of discovery and flood messages. ππ
value: a specific data structure expressing the value of the objective. The format is language dependent, with the constraint that it can be validly represented in CBOR [RFC8949]. π§
An important advantage of CBOR is that the value of an objective can be completely opaque to the GRASP core yet pass transparently through it to and from the ASA. Although the GRASP core must validate the format and syntax of GRASP messages, it cannot validate the value of an objective; all it can do is detect malformed CBOR. The handling of decoding errors depends on the CBOR library in use, but a corresponding error code ('CBORfail') is defined in the API and will be returned to the ASA if a faulty message can be assigned to a current GRASP session. However, it is the responsibility of each ASA to validate the value of a received objective, as discussed in Section 5.3 of [RFC8949]. If the programming language in use is suitably object-oriented, the GRASP API may deserialize the value and present it to the ASA as an object. If not, it will be presented as a CBOR data item. In all cases, the syntax and semantics of the objective value are the responsibility of the ASA. π
A requirement for all language mappings and all API implementations is that, regardless of what other options exist for a language-specific representation of the value, there is always an option to use a raw CBOR data item as the value. The API will then wrap this with CBOR Tag 24 as an encoded CBOR data item for transmission via GRASP, and unwrap it after reception. By this means, ASAs will be able to communicate regardless of programming language. πΈ
The 'name' and 'value' fields are of variable length. GRASP does not set a maximum length for these fields, but only for the total length of a GRASP message. Implementations might impose length limits. π
An example data structure definition for an objective in the C language, using at least the C99 version, and assuming the use of a particular CBOR library [libcbor], is:
typedef struct {
unsigned char *name;
uint8_t flags; // flag bits as defined by GRASP
uint8_t loop_count;
uint32_t value_size; // size of value in bytes
cbor_mutable_data cbor_value;
// CBOR bytestring (libcbor/cbor/data.h)
} objective;
An example data structure definition for an objective in the Python language (version 3.4 or later) is:
class objective:
"""A GRASP objective"""
def __init__(self, name):
self.name = name #Unique name (string)
self.negotiate = False #True if negotiation supported
self.dryrun = False #True if dry-run supported
self.synch = False #True if synchronization supported
self.loop_count = GRASP_DEF_LOOPCT # Default starting value
self.value = None #Place holder; any Python object
2.3.2.5. asa_locator π¦
okay so an 'asa_locator' is a data structure with these contents, and this is where we find where an ASA lives πΊοΈ
locator: the actual locator, either an IP address or an ASCII string. π
ifi (unsigned integer): the interface identifier index via which this was discovered (of limited use to most ASAs). π
expire (system dependent type): the time on the local system clock when this locator will expire from the cache. β°
The following covers all locator types currently supported by GRASP:
- is_ipaddress (Boolean) - True if the locator is an IP address. π
- is_fqdn (Boolean) - True if the locator is a Fully Qualified Domain Name (FQDN). π·οΈ
- is_uri (Boolean) - True if the locator is a URI. π
These options are mutually exclusive. Depending on the programming language, they could be represented as a bit pattern or an enumeration. π
diverted (Boolean): True if the locator was discovered via a Divert option. πͺ
protocol (unsigned integer): applicable transport protocol (IPPROTO_TCP or IPPROTO_UDP). These constants are defined in the CDDL specification of GRASP [RFC8990]. π
port (unsigned integer): applicable port number. πͺ
The 'locator' field is of variable length in the case of an FQDN or a URI. GRASP does not set a maximum length for this field, but only for the total length of a GRASP message. Implementations might impose length limits. π
It should be noted that when one ASA discovers the asa_locator of another, there is no explicit authentication mechanism. In accordance with the trust model provided by the secure ACP, ASAs are presumed to provide correct locators in response to discovery. See "Locator Options" (Section 2.9.5 of [RFC8990]) for further details. π«Ά
2.3.2.6. Tagged_objective π
a 'tagged_objective' is a data structure with these contents:
objective: an objective. π―
locator: the asa_locator associated with the objective, or a null value. π·οΈ
2.3.2.7. asa_handle π
okay this one is giving security vibes, even though an authentication and authorization scheme for ASAs has not been defined yet. The API still provides a very simple hook for one πͺ
When an ASA starts up, it registers itself with the GRASP core, which hands it an opaque handle. This handle is not cryptographically protected, but it would be difficult for a third party to predict. The ASA must present this handle in future calls. This mechanism will prevent some elementary errors or trivial attacks, such as an ASA manipulating an objective it has not registered to use. π
So, in most calls, an 'asa_handle' parameter is required. It is generated when an ASA first registers with GRASP, and the ASA must then store the asa_handle and use it in every subsequent GRASP call. Any call in which an invalid handle is presented will fail. It is an up to 32-bit opaque value (for example, represented as a uint32_t, depending on the language). Since it is only used locally, and not in GRASP messages, it is only required to be unique within the local GRASP instance. It is valid until the ASA terminates. It should be unpredictable; a possible implementation is to use the same mechanism that GRASP uses to generate Session IDs (see Section 2.3.2.8). πβ¨
2.3.2.8. Session_handle and Callbacks π
okay so in some calls, a 'session_handle' parameter is required. This is an opaque data structure as far as the ASA is concerned, and it's used to identify calls to the API as belonging to a specific GRASP session (see Section 2.2.3). It will be provided as a parameter in callback functions. As well as distinguishing calls from different sessions, it also lets GRASP detect and ignore calls from non-existent or timed-out sessions. π§ π
In an event loop implementation, callback functions (Section 2.2.1) may be supported for all API functions that involve waiting for a remote operation: π
discover() whose callback would be discovery_received(). π
request_negotiate() whose callback would be negotiate_step_received(). π€
negotiate_step() whose callback would be negotiate_step_received(). π£
listen_negotiate() whose callback would be negotiate_step_received(). π
synchronize() whose callback would be synchronization_received(). π«§
Further details of callbacks are implementation dependent. π
2.3.3. Registration β¨
okay bestie, these functions are how an ASA signs itself up with the GRASP module, plus the objectives it's gonna be messing with π . with no authorization model they're super simple, but they stop two ASAs from picking the same name and stop multiple ASAs from manipulating the same objective π₯. if an authorization model ever gets added to GRASP, these API calls would need to be updated to match π¦.
register_asa()π
every ASA must use this call before it makes any other API calls. no exceptions π
- Input parameter:
- name of the ASA (UTF-8 string)
- Return value:
errorcode(unsigned integer)asa_handle(unsigned integer)
- this sets up the state in the GRASP module for the calling entity (the ASA). if it works, you get an
asa_handleback, and the ASA has to show that handle in every call after this π«Ά. if it fails, the ASA has not been authorized and can't operate at all π. theasa_handlevalue is undefined in that case.
deregister_asa()π§Ή- Input parameters:
asa_handle(unsigned integer)- name of the ASA (UTF-8 string)
- Return value:
errorcode(unsigned integer)
- this removes all the state in the GRASP module for the calling entity (the ASA) and deregisters any objectives it has registered. and these actions must also happen automatically if an ASA exits. bye bye, clean exit β¨
- Note -- the ASA name is, strictly speaking, redundant in this call, but it's there to detect and reject erroneous deregistrations. it's like a bouncer checking your name twice π
- Input parameters:
register_objective()πΈ
ASAs must use this call for any objective whose value they need to transmit by negotiation, synchronization, or flooding.
- Input parameters:
asa_handle(unsigned integer)objective(structure)ttl(unsigned integer -- defaultGRASP_DEF_TIMEOUT)discoverable(Boolean -- default False)overlap(Boolean -- default False)local(Boolean -- default False)
- Return value:
errorcode(unsigned integer)
- this registers an objective that this ASA may modify and transmit to other ASAs by flooding or negotiation. it's not necessary to register an objective that's only received by GRASP synchronization or flooding. the
objectivebecomes a candidate for discovery. however, discovery responses should not be enabled until the ASA callslisten_negotiate()orlisten_synchronize(), showing that it's able to act as a responder. the ASA may negotiate the objective or send synchronization or flood data. registration isn't needed for "read-only" operations, i.e., when the ASA only wants to receive synchronization or flooded data for the objective concerned. lurker mode is valid π - the
ttlparameter is the valid lifetime (time to live) in milliseconds of any discovery response generated for this objective. the default value should be the GRASP default timeout (GRASP_DEF_TIMEOUT; see [RFC8990]). - if the parameter
discoverableis True, the objective is immediately discoverable. this is meant for objectives that are only defined for GRASP discovery and that don't support negotiation or synchronization. - if the parameter
overlapis True, more than one ASA may register this objective in the same GRASP instance. this matters for life cycle management of ASAs [ASA-GUIDE], and it must be used consistently for a given objective (always True or always False). consistency is everything, bestie π - if the parameter
localis True, discovery must return a link-local address. this feature is for objectives that must be restricted to the local link π. - this call may be repeated for multiple objectives.
deregister_objective()ποΈ- Input parameters:
asa_handle(unsigned integer)objective(structure)
- Return value:
errorcode(unsigned integer)
- the
objectivemust have been registered by the calling ASA. if it wasn't, this call fails. otherwise, it removes all state in the GRASP module for the given objective π.
- Input parameters:
2.3.4. Discovery π¦
discover()π
this function may be used by any ASA to discover peers handling a given objective.
- Input parameters:
asa_handle(unsigned integer)objective(structure)timeout(unsigned integer)minimum_TTL(unsigned integer)
- Return values:
errorcode(unsigned integer)locator_list(structure)
- this returns a list of discovered
asa_locators for the given objective. an empty list means no locators were discovered within the timeout. note that this structure includes all the fields described in Section 2.3.2.5. - the parameter
minimum_TTLmust be greater than or equal to zero. any locally cached locators for the objective whose remaining time to live in milliseconds is less than or equal tominimum_TTLare deleted first. sominimum_TTL= 0 will flush all entries. note that this won't affect sessions already in progress using the deleted locators π« . - if the parameter
timeoutis zero, any remaining locally cached locators for the objective are returned immediately, and no other action is taken. (so a call withminimum_TTLandtimeoutboth equal to zero is pointless π.) - if the parameter
timeoutis greater than zero, GRASP discovery is performed, and all results obtained before the timeout in milliseconds expires are returned. if no results are obtained, an empty list is returned after the timeout. that's not an error condition β¨. GRASP discovery isn't a deterministic process. if there are multiple nodes handling an objective, none, some, or all of them might be discovered before the timeout expires. - Asynchronous Mechanisms:
- Threaded implementation: this should be called in a separate thread if asynchronous operation is required.
- Event loop implementation: an additional in/out
session_handleparameter is used. if theerrorcodeparameter has the value 2 (noReply), no response has been received so far. thesession_handleparameter must be presented in subsequent calls. a callback may be used in the case of a non-zero timeout π§.
2.3.5. Negotiation π€
since the negotiation mechanism is different from a typical client/server exchange, Figure 2 shows the sequence of calls and GRASP messages in a negotiation. note that after the first protocol exchange, the process is symmetrical, with negotiating steps strictly alternating between the two sides. either side can end the negotiation. also, the side that's due to respond next can insert a delay at any time, to extend the other side's timeout. this would be used, for example, if an ASA needed to negotiate with a third party before continuing with the current negotiation π§ .
the loop count embedded in the objective that's the subject of negotiation is initialized by the ASA that starts a negotiation, and is then decremented by the GRASP core at each step, prior to sending each M_NEGOTIATE message. if it reaches zero, the negotiation will fail, and each side will receive an error code π.
Initiator Responder
--------- ---------
listen_negotiate() \ Await request
request_negotiate()
M_REQ_NEG -> negotiate_step() \ Open session,
<- M_NEGOTIATE / start negotiation
negotiate_step()
M_NEGOTIATE -> negotiate_step() \ Continue
<- M_NEGOTIATE / negotiation
...
negotiate_wait() \ Insert
M_WAIT -> / delay
negotiate_step()
M_NEGOTIATE -> negotiate_step() \ Continue
<- M_NEGOTIATE / negotiation
negotiate_step()
M_NEGOTIATE -> end_negotiate() \ End
<- M_END / negotiation
\ Process results
Figure 2: Negotiation Sequence
as the negotiation goes on, each side updates the value of the objective in line with its own semantics, as defined in the specification of the objective. although lots of objectives will have values that can be ordered, so negotiation can be a simple bidding process, it's not a requirement π―.
failure to agree, a timeout, or loop count exhaustion may all end a negotiation session, but none of these cases are protocol failures. no drama, just a session ending π«Ά
request_negotiate()π
this function is used by any ASA to start negotiating a GRASP objective as a requester (client).
- Input parameters:
asa_handle(unsigned integer)objective(structure)peer(asa_locator)timeout(unsigned integer)
- Return values:
errorcode(unsigned integer)session_handle(structure) (undefined unless successful)proffered_objective(structure) (undefined unless successful)reason(string) (empty unless negotiation declined)
- this function opens a negotiation session between two ASAs. note that GRASP doesn't currently support multiparty negotiation, which would need to be added as an extended function π.
- the
objectiveparameter must include the requested value, and its loop count should be set to a suitable starting value by the ASA. if not, the GRASP default will apply. - note that a given negotiation session may or may not be a dry-run negotiation, but the two modes must not be mixed in a single session π«.
- the
peerparameter is the target node. it must be anasa_locatoras returned bydiscover(). ifpeeris null, GRASP discovery is automatically performed first to find a suitable peer (i.e., any node that supports the objective in question) π. - the
timeoutparameter is described in Section 2.3.2.3. - if the
errorcodereturn value is 0, the negotiation has successfully started. there are then two cases:- the
session_handleparameter is null. in this case, the negotiation has succeeded with one exchange of messages, and the peer has accepted the request. the returnedproffered_objectivecontains the value accepted by the peer, which is therefore equal to the value in the requestedobjective. for this reason, no session handle is needed, since the session has ended β .
- the
- okay so the
session_handleis not null π which means negotiation has to keep going bestie. Thesession_handlemust be presented in all subsequent negotiation steps π«Ά The returnedproffered_objectiveholds the first value the negotiation peer proffers in the first exchange of messages. In other words, it's a counter-offer π The contents of this instance of the objective must be used to prepare the next negotiation step (seenegotiate_step()below) because it has the updated loop count sent by the peer. GRASP automatically decrements the loop count by 1 at each step and returns an error if it hits zero π Since that ends the negotiation, the other end experiences a timeout, which terminates its end of the session. Rip π
This function must be followed by calls to negotiate_step and/or negotiate_wait and/or end_negotiate until the negotiation ends. request_negotiate may then be called again to start a new negotiation β¨
- If the
errorcodeparameter has the value1('declined'), the negotiation has been declined by the peer (M_END and O_DECLINE features of GRASP) π ββοΈ Thereasonstring is then available for information and diagnostic use, but it may be a null string. For this and any other error code, an exponential backoff is recommended before any retry (see Section 3). Patience is a whole vibe πΈ - Asynchronous Mechanisms:
- Threaded implementation: This should be called in a separate thread if asynchronous operation is required π§΅
- Event loop implementation: The
session_handleparameter is used to distinguish multiple simultaneous sessions. If theerrorcodeparameter has the value2('noReply'), no response has been received so far π» Thesession_handleparameter must be presented in subsequent calls.
- Use of dry-run mode must be consistent within a GRASP session. The state of the
dryflag in the initialrequest_negotiate()call must be the same in all subsequent negotiation steps of the same session. The semantics of the dry-run mode are built into the ASA; GRASP merely carries the flag bit π§ - Special note for the ACP infrastructure ASA: It is likely that this ASA will need to discover and negotiate with its peers in each of its on-link neighbors. It will therefore need to know not only the link-local IP address but also the physical interface and transport port for connecting to each neighbor. One implementation approach to this is to include these details in the
session_handledata structure, which is opaque to normal ASAs π - listen_negotiate()
This function is used by an ASA to start acting as a negotiation responder (listener) for a given GRASP objective π
- Input parameters:
- asa_handle (unsigned integer)
- objective (structure)
- Return values:
- errorcode (unsigned integer)
- session_handle (structure) (undefined unless successful)
- requested_objective (structure) (undefined unless successful)
This function instructs GRASP to listen for negotiation requests for the given objective. It also enables discovery responses for the objective, as mentioned under register_objective() in Section 2.3.3 π¦
- Asynchronous Mechanisms:
- Threaded implementation: It will block waiting for an incoming request, so it should be called in a separate thread if asynchronous operation is required. Unless there is an unexpected failure, this call only returns after an incoming negotiation request. If the ASA supports multiple simultaneous transactions, a new sub-thread must be spawned for each new session, so that
listen_negotiate()can be called again immediately πββοΈ - Event loop implementation: A
session_handleparameter is used to distinguish individual sessions. If the ASA supports multiple simultaneous transactions, a new event must be inserted in the event loop for each new session, so thatlisten_negotiate()can be reactivated immediately.
- Threaded implementation: It will block waiting for an incoming request, so it should be called in a separate thread if asynchronous operation is required. Unless there is an unexpected failure, this call only returns after an incoming negotiation request. If the ASA supports multiple simultaneous transactions, a new sub-thread must be spawned for each new session, so that
This call only returns (threaded model) or triggers (event loop) after an incoming negotiation request. When this occurs, requested_objective contains the first value requested by the negotiation peer. The contents of this instance of the objective must be used in the subsequent negotiation call because it contains the loop count sent by the negotiation peer. The session_handle must be presented in all subsequent negotiation steps π―
This function must be followed by calls to negotiate_step and/or negotiate_wait and/or end_negotiate until the negotiation ends.
If an ASA is capable of handling multiple negotiations simultaneously, it may call listen_negotiate simultaneously from multiple threads, or insert multiple events. The API and GRASP implementation must support re-entrant use of the listening state and the negotiation calls. Simultaneous sessions will be distinguished by the threads or events themselves, the GRASP session handles, and the underlying unicast transport sockets π multitasking queen π
- stop_listen_negotiate()
This function is used by an ASA to stop acting as a responder (listener) for a given GRASP objective π
- Input parameters:
- asa_handle (unsigned integer)
- objective (structure)
- Return value:
- errorcode (unsigned integer)
It instructs GRASP to stop listening for negotiation requests for the given objective, i.e., cancels listen_negotiate.
- Asynchronous Mechanisms:
- Threaded implementation: Must be called from a different thread than
listen_negotiate. - Event loop implementation: No special considerations π
- Threaded implementation: Must be called from a different thread than
- negotiate_step()
This function is used by either ASA in a negotiation session to make the next step in negotiation π
- Input parameters:
- asa_handle (unsigned integer)
- session_handle (structure)
- objective (structure)
- timeout (unsigned integer) as described in Section 2.3.2.3
- Return values:
- Exactly as for
request_negotiate
- Exactly as for
It executes the next negotiation step with the peer. The objective parameter contains the next value being proffered by the ASA in this step. It must also contain the latest loop_count value received from request_negotiate() or negotiate_step().
- Asynchronous Mechanisms:
- Threaded implementation: Usually called in the same thread as the preceding
request_negotiateorlisten_negotiate, with the same value ofsession_handle. - Event loop implementation: Must use the same value of
session_handlereturned by the precedingrequest_negotiateorlisten_negotiate.
- Threaded implementation: Usually called in the same thread as the preceding
- negotiate_wait()
This function is used by either ASA in a negotiation session to delay the next step in negotiation β³
- Input parameters:
- asa_handle (unsigned integer)
- session_handle (structure)
- timeout (unsigned integer)
- Return value:
- errorcode (unsigned integer)
It requests the remote peer to delay the negotiation session by timeout milliseconds, thereby extending the original timeout. This function simply triggers a GRASP Confirm Waiting message (see [RFC8990] for details) π«§
- Asynchronous Mechanisms:
- Threaded implementation: Called in the same thread as the preceding
request_negotiateorlisten_negotiate, with the same value ofsession_handle. - Event loop implementation: Must use the same value of
session_handlereturned by the precedingrequest_negotiateorlisten_negotiate.
- Threaded implementation: Called in the same thread as the preceding
- end_negotiate()
This function is used by either ASA in a negotiation session to end a negotiation π
- Input parameters:
- asa_handle (unsigned integer)
- session_handle (structure)
- result (Boolean)
- reason (UTF-8 string)
- Return value:
- errorcode (unsigned integer)
End the negotiation session:
result= True for accept (successful negotiation), and False for decline (failed negotiation).reason= string describing reason for decline (may be null; ignored if accept).- Asynchronous Mechanisms:
- Threaded implementation: Called in the same thread as the preceding
request_negotiateorlisten_negotiate, with the same value ofsession_handle. - Event loop implementation: Must use the same value of
session_handlereturned by the precedingrequest_negotiateorlisten_negotiate.
- Threaded implementation: Called in the same thread as the preceding
2.3.6. Synchronization and Flooding πβ¨
Okay so this part is all about getting the latest GRASP objective values, and the flooding stuff that spreads them around the whole Autonomic Network π It's giving "everyone gets the tea at once" energy, bestie π
- synchronize()
This function is used by any ASA to cause synchronization of a GRASP objective as a requester (client). π«Ά
- Input parameters:
asa_handle (unsigned integer)
objective (structure)
peer (asa_locator)
timeout (unsigned integer)
- Return values:
errorcode (unsigned integer)
result (structure) (undefined unless successful)
- This call requests the synchronized value of the given 'objective'. π
- If the 'peer' parameter is null, and the objective is already available in the local cache, the flooded objective is returned immediately in the 'result' parameter. In this case, the 'timeout' is ignored. β‘ No waiting, just vibes.
- If the 'peer' parameter is not null, or a cached value is not available, synchronization with a discovered ASA is performed. If successful, the retrieved objective is returned in the 'result' value. π
- The 'peer' parameter is an 'asa_locator' as returned by discover(). If 'peer' is null, GRASP discovery is automatically performed first to find a suitable peer (i.e., any node that supports the objective in question). π It finds someone who can actually help, iykyk.
- The 'timeout' parameter is described in Section 2.3.2.3. π¦
- This call should be repeated whenever the latest value is needed. πΈ
- Asynchronous Mechanisms:
Threaded implementation: Call in a separate thread if asynchronous operation is required. π§
Event loop implementation: An additional in/out 'session_handle' parameter is used, as in request_negotiate(). If the 'errorcode' parameter has the value 2 ('noReply'), no response has been received so far. The 'session_handle' parameter must be presented in subsequent calls. π Keep that handle, it's your ticket.
- In the case of failure, an exponential backoff is recommended before retrying (Section 3). π Don't spam the retry button, ngl.
- listen_synchronize()
This function is used by an ASA to start acting as a synchronization responder (listener) for a given GRASP objective. π
- Input parameters:
asa_handle (unsigned integer)
objective (structure)
- Return value:
errorcode (unsigned integer)
- This instructs GRASP to listen for synchronization requests for the given objective and to respond with the value given in the 'objective' parameter. It also enables discovery responses for the objective, as mentioned under register_objective() in Section 2.3.3. β¨ Main character listener energy.
- This call is non-blocking and may be repeated whenever the value changes. π
- stop_listen_synchronize()
This function is used by an ASA to stop acting as a synchronization responder (listener) for a given GRASP objective. π₯
- Input parameters:
asa_handle (unsigned integer)
objective (structure)
- Return value:
errorcode (unsigned integer)
- This call instructs GRASP to stop listening for synchronization requests for the given 'objective', i.e., it cancels a previous listen_synchronize. π ββοΈ Plot twist: it undoes the listening.
- flood()
This function is used by an ASA to flood one or more GRASP objectives throughout the Autonomic Network. π
Note that each GRASP node caches all flooded objectives that it receives, until each one's time to live expires. Cached objectives are tagged with their origin as well as an expiry time, so multiple copies of the same objective may be cached simultaneously. Further details are given in "Flood Synchronization Message" (Section 2.8.11 of [RFC8990]). π The deets live in [RFC8990] if you want them.
- Input parameters:
asa_handle (unsigned integer)
ttl (unsigned integer)
tagged_objective_list (structure)
- Return value:
errorcode (unsigned integer)
- This call instructs GRASP to flood the given synchronization objective(s) and their value(s) and associated locator(s) to all GRASP nodes. π£
- The 'ttl' parameter is the valid lifetime (time to live) of the flooded data in milliseconds (0 = infinity). β³ Zero means it lives forever, periodt.
- The 'tagged_objective_list' parameter is a list of one or more 'tagged_objective' couplets. The 'locator' parameter that tags each objective is normally null but may be a valid 'asa_locator'. Infrastructure ASAs needing to flood an {address, protocol, port} 3-tuple with an objective create an asa_locator object to do so. If the IP address in that locator is the unspecified address ('::'), it is replaced by the link- local address of the sending node in each copy of the flood multicast, which will be forced to have a loop count of 1. This feature is for objectives that must be restricted to the local link. π§ Local-only drama, kept on the link where it belongs.
- The function checks that the ASA registered each objective. π
- This call may be repeated whenever any value changes. π
- get_flood()
This function is used by any ASA to obtain the current value of a flooded GRASP objective. π«§
- Input parameters:
asa_handle (unsigned integer)
objective (structure)
- Return values:
errorcode (unsigned integer)
tagged_objective_list (structure) (undefined unless successful)
- This call instructs GRASP to return the given synchronization objective if it has been flooded and its lifetime has not expired. π«
- The 'tagged_objective_list' parameter is a list of 'tagged_objective' couplets, each one being a copy of the flooded objective and a corresponding locator. Thus, if the same objective has been flooded by multiple ASAs, the recipient can distinguish the copies. π΅οΈββοΈ Copies get labelled so nobody gets mixed up.
- Note that this call is for advanced ASAs. In a simple case, an ASA can simply call synchronize() in order to get a valid flooded objective. π§ Advanced mode is for the big brains.
- expire_flood()
This function may be used by an ASA to expire specific entries in the local GRASP flood cache. ποΈ
- Input parameters:
asa_handle (unsigned integer)
tagged_objective (structure)
- Return value:
errorcode (unsigned integer)
- This is a call that can only be used after a preceding call to get_flood() by an ASA that is capable of deciding that the flooded value is stale or invalid. Use with care. β οΈ Handle with care, no cap.
- The 'tagged_objective' parameter is the one to be expired. π
2.3.7. Invalid Message Function π«
- send_invalid()
This function may be used by any ASA to stop an ongoing GRASP session. π
- Input parameters:
asa_handle (unsigned integer)
session_handle (structure)
info (bytes)
- Return value:
errorcode (unsigned integer)
- Sends a GRASP Invalid message (M_INVALID), as described in [RFC8990]. It should not be used if end_negotiate() would be sufficient. Note that this message may be used in response to any unicast GRASP message that the receiver cannot interpret correctly. In most cases, this message will be generated internally by a GRASP implementation. π Usually the stack handles this for you.
'info' = optional diagnostic data supplied by the ASA. It may be raw bytes from the invalid message. π§Ύ
- Security Considerations ππ
Security considerations for the GRASP protocol are discussed in [RFC8990]. These include denial-of-service issues, even though these are considered a low risk in the ACP. In various places, GRASP recommends an exponential backoff. An ASA using the API should use exponential backoff after failed discover(), req_negotiate(), or synchronize() operations. The timescale for such backoffs depends on the semantics of the GRASP objective concerned. Additionally, a flood() operation should not be repeated at shorter intervals than is useful. The appropriate interval depends on the semantics of the GRASP objective concerned. These precautions are intended to assist the detection of denial-of-service attacks. π DoS is not it, so back off and space your floods out.
As a general precaution, all ASAs able to handle multiple negotiation or synchronization requests in parallel may protect themselves against a denial-of-service attack by limiting the number of requests they handle simultaneously and silently discarding excess requests. It might also be useful for the GRASP core to limit the number of objectives registered by a given ASA, the total number of ASAs registered, and the total number of simultaneous sessions, to protect system resources. During times of high autonomic activity, such as recovery from widespread faults, ASAs may experience many GRASP session failures. Guidance on making ASAs suitably robust is given in [ASA-GUIDE]. π‘οΈ Limit your queue, drop the extras, stay chill.
As noted earlier, the trust model is that all ASAs in a given Autonomic Network communicate via a secure autonomic control plane; therefore, they trust each other's messages. Specific authorization of ASAs to use particular GRASP objectives is a subject for future study, also briefly discussed in [RFC8990]. π€ The ACP is the bouncer, so everyone inside is trusted for now. Authorization is still a work in progress, bestie.
The careful reader will observe that a malicious ASA could extend a negotiation session indefinitely by use of the negotiate_wait() function or by manipulating the loop count of an objective. A robustly implemented ASA could detect such behavior by a peer and break off negotiation. π¨ Red flag alert: a sneaky ASA could drag a session on forever, so a solid one should spot that and bounce.
The 'asa_handle' is used in the API as a first line of defense against a malware process attempting to imitate a legitimately registered ASA. The 'session_handle' is used in the API as a first line of defense against a malware process attempting to hijack a GRASP session. Both these handles are likely to be created using GRASP's 32-bit pseudorandom Session ID. By construction, GRASP avoids the risk of Session ID collisions (see "Session Identifier (Session ID)", Section 2.7 of [RFC8990]). There remains a finite probability that an attacker could guess a Session ID, session_handle, or asa_handle. However, this would only be of value to an attacker that had already penetrated the ACP, which would allow many other simpler forms of attack than hijacking GRASP sessions. π΅οΈ Handles are the first line of defense against imposters and session hijackers, and guessing one would only help someone already inside the ACP.
- IANA Considerations π§
This document has no IANA actions. π Nothing to do over at IANA this time.
- References π
5.1. Normative References π
[RFC8610] Birkholz, H., Vigano, C., and C. Bormann, "Concise Data Definition Language (CDDL): A Notational Convention to Express Concise Binary Object Representation (CBOR) and JSON Data Structures", RFC 8610, DOI 10.17487/RFC8610, June 2019, <https://www.rfc-editor.org/info/rfc8610>.
[RFC8949] Bormann, C. and P. Hoffman, "Concise Binary Object Representation (CBOR)", STD 94, RFC 8949, DOI 10.17487/RFC8949, December 2020, <https://www.rfc-editor.org/info/rfc8949>.
[RFC8990] Bormann, C., Carpenter, B., Ed., and B. Liu, Ed., "GeneRic Autonomic Signaling Protocol (GRASP)", RFC 8990, DOI 10.17487/RFC8990, May 2021, <https://www.rfc-editor.org/info/rfc8990>.
5.2. Informative References πβ¨
Okay bestie, these are the extra-credit reads π€π¦ Here's the full list, with the URLs kept intact:
[ANIMA-COORD] Ciavaglia, L. and P. Peloso, "Autonomic Functions Coordination", Work in Progress, Internet-Draft, draft-ciavaglia-anima-coordination-01, 21 March 2016, <https://tools.ietf.org/html/draft-ciavaglia-anima-coordination-01>.
[ASA-GUIDE] Carpenter, B., Ciavaglia, L., Jiang, S., and P. Peloso, "Guidelines for Autonomic Service Agents", Work in Progress, Internet-Draft, draft-ietf-anima-asa-guidelines-00, 14 November 2020, <https://tools.ietf.org/html/draft-ietf-anima-asa-guidelines-00>.
[GRASP-DISTRIB] Liu, B., Xiao, X., Hecker, A., Jiang, S., Despotovic, Z., and B. Carpenter, "Information Distribution over GRASP", Work in Progress, Internet-Draft, draft-ietf-anima-grasp-distribution-02, 8 March 2021, <https://tools.ietf.org/html/draft-ietf-anima-grasp-distribution-02>.
[libcbor] Kalvoda, P., "libcbor - libcbor 0.8.0 documentation", April 2021, <https://libcbor.readthedocs.io/>.
[RFC8993] Behringer, M., Ed., Carpenter, B., Eckert, T., Ciavaglia, L., and J. Nobre, "A Reference Model for Autonomic Networking", RFC 8993, DOI 10.17487/RFC8993, May 2021, <https://www.rfc-editor.org/info/rfc8993>.
[RFC8994] Eckert, T., Ed., Behringer, M., Ed., and S. Bjarnason, "An Autonomic Control Plane (ACP)", RFC 8994, DOI 10.17487/RFC8994, May 2021, <https://www.rfc-editor.org/info/rfc8994>.
[RFC8995] Pritikin, M., Richardson, M., Eckert, T., Behringer, M., and K. Watsen, "Bootstrapping Remote Secure Key Infrastructure (BRSKI)", RFC 8995, DOI 10.17487/RFC8995, May 2021, <https://www.rfc-editor.org/info/rfc8995>.
Appendix A. Error Codes π¨π
Okay so this appendix is the official list of error codes, based on what implementers have actually run into π οΈ It also has suggested symbolic names and the descriptive strings in English. Full API implementations are expected to localise those strings, and you'll probably need more error codes depending on your implementation details π
Some codes can only come back from one or two functions, so those are tagged. The rest can show up from loads of functions π The noSecurity error gets returned to most calls when GRASP is running in an insecure mode (so, no secure substrate like the ACP) π The one exception is the specific DULL usage mode from "Discovery Unsolicited Link-Local (DULL) GRASP" (Section 2.5.2 of [RFC8990]. Ngl this table is a lot, but it's giving organised π
+================+=======+=================================+
| Name | Error | Description |
| | Code | |
+================+=======+=================================+
| ok | 0 | "OK" |
+----------------+-------+---------------------------------+
| declined | 1 | "Declined" (req_negotiate, |
| | | negotiate_step) |
+----------------+-------+---------------------------------+
| noReply | 2 | "No reply" (indicates waiting |
| | | state in event loop calls) |
+----------------+-------+---------------------------------+
| unspec | 3 | "Unspecified error" |
+----------------+-------+---------------------------------+
| ASAfull | 4 | "ASA registry full" |
| | | (register_asa) |
+----------------+-------+---------------------------------+
| dupASA | 5 | "Duplicate ASA name" |
| | | (register_asa) |
+----------------+-------+---------------------------------+
| noASA | 6 | "ASA not registered" |
+----------------+-------+---------------------------------+
| notYourASA | 7 | "ASA registered but not by you" |
| | | (deregister_asa) |
+----------------+-------+---------------------------------+
| notBoth | 8 | "Objective cannot support both |
| | | negotiation and |
| | | synchronization" (register_obj) |
+----------------+-------+---------------------------------+
| notDry | 9 | "Dry-run allowed only with |
| | | negotiation" (register_obj) |
+----------------+-------+---------------------------------+
| notOverlap | 10 | "Overlap not supported by this |
| | | implementation" (register_obj) |
+----------------+-------+---------------------------------+
| objFull | 11 | "Objective registry full" |
| | | (register_obj) |
+----------------+-------+---------------------------------+
| objReg | 12 | "Objective already registered" |
| | | (register_obj) |
+----------------+-------+---------------------------------+
| notYourObj | 13 | "Objective not registered by |
| | | this ASA" |
+----------------+-------+---------------------------------+
| notObj | 14 | "Objective not found" |
+----------------+-------+---------------------------------+
| notNeg | 15 | "Objective not negotiable" |
| | | (req_negotiate, |
| | | listen_negotiate) |
+----------------+-------+---------------------------------+
| noSecurity | 16 | "No security" |
+----------------+-------+---------------------------------+
| noDiscReply | 17 | "No reply to discovery" |
| | | (req_negotiate) |
+----------------+-------+---------------------------------+
| sockErrNegRq | 18 | "Socket error sending |
| | | negotiation request" |
| | | (req_negotiate) |
+----------------+-------+---------------------------------+
| noSession | 19 | "No session" |
+----------------+-------+---------------------------------+
| noSocket | 20 | "No socket" |
+----------------+-------+---------------------------------+
| loopExhausted | 21 | "Loop count exhausted" |
| | | (negotiate_step) |
+----------------+-------+---------------------------------+
| sockErrNegStep | 22 | "Socket error sending |
| | | negotiation step" |
| | | (negotiate_step) |
+----------------+-------+---------------------------------+
| noPeer | 23 | "No negotiation peer" |
| | | (req_negotiate, negotiate_step) |
+----------------+-------+---------------------------------+
| CBORfail | 24 | "CBOR decode failure" |
| | | (req_negotiate, negotiate_step, |
| | | synchronize) |
+----------------+-------+---------------------------------+
| invalidNeg | 25 | "Invalid Negotiate message" |
| | | (req_negotiate, negotiate_step) |
+----------------+-------+---------------------------------+
| invalidEnd | 26 | "Invalid end message" |
| | | (req_negotiate, negotiate_step) |
+----------------+-------+---------------------------------+
| noNegReply | 27 | "No reply to negotiation step" |
| | | (req_negotiate, negotiate_step) |
+----------------+-------+---------------------------------+
| noValidStep | 28 | "No valid reply to negotiation |
| | | step" (req_negotiate, |
| | | negotiate_step) |
+----------------+-------+---------------------------------+
| sockErrWait | 29 | "Socket error sending wait |
| | | message" (negotiate_wait) |
+----------------+-------+---------------------------------+
| sockErrEnd | 30 | "Socket error sending end |
| | | message" (end_negotiate, |
| | | send_invalid) |
+----------------+-------+---------------------------------+
| IDclash | 31 | "Incoming request Session ID |
| | | clash" (listen_negotiate) |
+----------------+-------+---------------------------------+
| notSynch | 32 | "Not a synchronization |
| | | objective" (synchronize, |
| | | get_flood) |
+----------------+-------+---------------------------------+
| notFloodDisc | 33 | "Not flooded and no reply to |
| | | discovery" (synchronize) |
+----------------+-------+---------------------------------+
| sockErrSynRq | 34 | "Socket error sending synch |
| | | request" (synchronize) |
+----------------+-------+---------------------------------+
| noListener | 35 | "No synch listener" |
| | | (synchronize) |
+----------------+-------+---------------------------------+
| noSynchReply | 36 | "No reply to synchronization |
| | | request" (synchronize) |
+----------------+-------+---------------------------------+
| noValidSynch | 37 | "No valid reply to |
| | | synchronization request" |
| | | (synchronize) |
+----------------+-------+---------------------------------+
| invalidLoc | 38 | "Invalid locator" (flood) |
+----------------+-------+---------------------------------+
Table 1: Error Codes
Acknowledgements π«Άπ
Huge thanks to the people who made excellent suggestions: Ignas Bagdonas, Carsten Bormann, Laurent Ciavaglia, Roman Danyliw, Toerless Eckert, Benjamin Kaduk, Erik Kline, Murray Kucherawy, Paul Kyzivat, Guangpeng Li, Michael Richardson, Joseph Salowey, Γric Vyncke, Magnus Westerlund, Rob Wilton, and other participants in the ANIMA WG and the IESG ππΈ
Authors' Addresses π
okay bestie, here are the four brilliant minds who wrote this thing, with their mailing addresses and emails so you can reach out π¦β¨
Brian E. Carpenter
School of Computer Science
University of Auckland
PB 92019
Auckland 1142
New Zealand
Email: brian.e.carpenter@gmail.com
Bing Liu (editor)
Huawei Technologies
Q14, Huawei Campus
No.156 Beiqing Road
Hai-Dian District, Beijing
100095
China
Email: leo.liubing@huawei.com
Bing Liu is the editor, so they're the one keeping the whole document in shape π«Ά
Wendong Wang
BUPT University
Beijing University of Posts & Telecom.
No.10 Xitucheng Road
Hai-Dian District, Beijing 100876
China
Email: wdwang@bupt.edu.cn
Xiangyang Gong
BUPT University
Beijing University of Posts & Telecom.
No.10 Xitucheng Road
Hai-Dian District, Beijing 100876
China
Email: xygong@bupt.edu.cn
and that's the whole squad, periodt ππΈ
π¦ where this page comes from
- ietf: rfc8991 2021-05
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms