RFC 6369
Forwarding and Control Element Separation (ForCES) Implementation Experience
Forwarding and Control Element Separation (ForCES) Implementation Experience π
Okay bestie, this is RFC 6369 π¦ It's from the IETF, written by E. Haleplidis, O. Koufopavlou, and S. Denazis from the University of Patras, and it's an Informational doc, so it's not a standards-track spec. It was published in September 2011 and has ISSN 2070-1721 β¨ The title block doesn't list anything it obsoletes or updates, so it's standing on its own π
Abstract β¨
So ForCES (Forwarding and Control Element Separation) is a standard communication and control mechanism that lets a Control Element (CE) control how a Forwarding Element (FE) behaves π§ This doc shares what it's actually like to implement the ForCES protocol and model. The goal is to help people out with examples and possible strategies for building it π«Ά
Status of This Memo πΈ
This document is not an Internet Standards Track specification. It's published just for informational purposes, so don't treat it like a rulebook π
It's a product of the Internet Engineering Task Force (IETF) and represents the consensus of the IETF community. It got public review and was approved for publication by the Internet Engineering Steering Group (IESG). Not every IESG-approved doc is a candidate for any level of Internet Standard, so check Section 2 of RFC 5741 if you're curious about that π€
For the current status, any errata, and how to send feedback, go to http://www.rfc-editor.org/info/rfc6369 π
Copyright Notice π
Copyright (c) 2011 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 (http://trustee.ietf.org/license-info) as in effect on the publication date. Please read those carefully, because they spell out your rights and restrictions for this doc. Code Components extracted from this document must include the 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
1.1. Document Goal . . . . . . . . . . . . . . . . . . . . . . 3
2. Terminology and Conventions . . . . . . . . . . . . . . . . . 3
3. ForCES Architecture . . . . . . . . . . . . . . . . . . . . . 4
3.1. Pre-Association Setup - Initial Configuration . . . . . . 5
3.2. TML . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
3.3. Model . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.3.1. Components . . . . . . . . . . . . . . . . . . . . . . 6
3.3.2. LFBs . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.4. Protocol . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.4.1. TLVs . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.4.2. Message Deserialization . . . . . . . . . . . . . . . 13
3.4.3. Message Serialization . . . . . . . . . . . . . . . . 15
4. Development Platforms . . . . . . . . . . . . . . . . . . . . 15
5. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 16
6. Security Considerations . . . . . . . . . . . . . . . . . . . 16
7. References . . . . . . . . . . . . . . . . . . . . . . . . . . 17
7.1. Normative References . . . . . . . . . . . . . . . . . . . 17
7.2. Informative References . . . . . . . . . . . . . . . . . . 17
1. Introduction β¨
So ForCES is an architectural framework plus associated protocols that standardize how info gets exchanged between the control plane and the forwarding plane inside a ForCES Network Element (ForCES NE) π§ [RFC3654] defines the ForCES requirements, and [RFC3746] defines the ForCES framework π
The ForCES protocol runs in a master-slave mode: Forwarding Elements (FEs) are slaves and Control Elements (CEs) are masters π It has commands for moving Logical Functional Block (LFB) configuration info, association setup, status, and event notifications, and more. Go read the Forwarding and Control Element Separation Protocol [RFC5810] for the deets π
[RFC5812] shows a formal way to define FE LFBs using XML π«Ά When LFBs are formally created, their configuration components, capabilities, and associated events get defined too. That means the ForCES protocol controls the LFBs inside the FE in a standardized way β¨
The Transport Mapping Layer (TML) carries the protocol messages π¦ This is where transport-level reliability, congestion control, multicast, ordering, and similar issues get handled. More than one TML is expected to be standardized, and each one might vary its implementation based on what the underlying media and transport can do. Since each TML is standardized, interoperability is guaranteed as long as both endpoints support the same TML π All ForCES protocol layer implementations must be portable across all TMLs. Even though more than one TML may be standardized, every ForCES implementation must implement the Stream Control Transmission Protocol (SCTP) TML [RFC5811] π That's the one non-negotiable, bestie π
The Forwarding and Control Element Separation Applicability Statement [RFC6041] covers the areas where ForCES can actually be used πΈ
1.1. Document Goal π
This doc shares what it's like to implement the ForCES protocol and model. Its main goal is to offer alternatives, ideas, and proposals for how it can be implemented. It is not here to tell anyone how they have to implement it π
It also points out possible problems and potential choices, to help implementors build their own products π
Also, this doc assumes you already know the three main ForCES RFCs: the Forwarding and Control Element Separation Protocol [RFC5810], the Forwarding and Control Element Separation Forwarding Element Model [RFC5812], and the SCTP-Based Transport Mapping Layer (TML) for the Forwarding and Control Element Separation Protocol [RFC5811] π
2. Terminology and Conventions π§
The terminology here matches the Forwarding and Control Element Separation Protocol [RFC5810], and some definitions are copied straight from that doc π
Control Element (CE): A logical entity that implements the ForCES protocol and uses it to instruct one or more FEs on how to process packets. CEs handle things like running control and signaling protocols π
Forwarding Element (FE): A logical entity that implements the ForCES protocol. FEs use the underlying hardware to do per-packet processing and handling, as directed or controlled by one or more CEs through the ForCES protocol β‘
LFB (Logical Functional Block): The basic building block the ForCES protocol operates on. An LFB is a well-defined, logically separable functional block that lives in an FE and is controlled by the CE through the ForCES protocol π¦ An LFB may sit in the FE's data path and process packets, or it may be purely an FE control or configuration entity that the CE operates on. Note that the LFB is a functionally accurate abstraction of the FE's processing capabilities, not a hardware-accurate picture of the FE implementation πΈ
LFB Class and LFB Instance: LFBs are sorted into LFB classes. An LFB instance represents the existence of an LFB class (or type), and there may be multiple instances of the same LFB class (or type) in one FE π An LFB class is identified by an LFB class ID, and an LFB instance is identified by an LFB instance ID. So an LFB class ID paired with an LFB instance ID uniquely specifies an LFB existence π
LFB Component: The operational parameters of the LFBs that must be visible to the CEs are modeled in the FE model as LFB components. They include things like flags, single parameter arguments, complex arguments, and tables that the CE can read and/or write through the ForCES protocol π
ForCES Protocol: The ForCES architecture can use multiple protocols, but the terms "ForCES protocol" and "protocol" refer to the Fp reference points in the ForCES framework [RFC3746]. This protocol does not apply to CE-to-CE communication, FE-to-FE communication, or communication between FE and CE Managers. Basically, the ForCES protocol works in a master-slave mode where FEs are slaves and CEs are masters. This document defines the specifications for this ForCES protocol π«Ά
3. ForCES Architecture π
ForCES has been through two successful interoperability tests, and very few issues came up, and the ones that did got fixed π
This section talks about the ForCES architecture, the implementation challenges, and ways to get past those challenges π
3.1. Pre-Association Setup - Initial Configuration π§
The initial configuration of the FE and the CE is handled by the FE Manager and the CE Manager, respectively. These entities haven't been standardized yet π
The simplest option is static configuration files that act as the Managers and get read by FEs and CEs π
For more dynamic setups, the Managers are expected to talk to each other and exchange details about the associations π¦ Any developer can build any Manager, but they should at least be able to exchange the details below π
From the FE Manager side:
- FE Identifiers (FEIDs).
- FE IP addresses, if the FEs and CEs will be communicating via network.
- TML. The TML that will be used. If this is omitted, then SCTP must be chosen as default.
- TML priority ports. If this is omitted as well, then the CE must use the default values from the respective TML RFC.
From the CE Manager side:
- CE Identifiers (CEIDs).
- CE IP addresses, if the FEs and CEs will be communicating via network.
- TML. The TML that will be used. If this is omitted, then SCTP must be chosen as default.
- TML priority ports. If this is omitted as well, then the FE must use the default values from the respective TML RFC.
3.2. TML π
All ForCES implementations must support the SCTP TML π Even if a developer picks another TML, SCTP is mandatory and must be supported. No skipping it, periodt π
There are a few TML issues a developer should keep an eye on β¨
- Security. TML must be secure according to the respective RFC. For SCTP, you have to use IPsec π
- Remote connection. ForCES is meant to be used locally, but both interoperability tests proved it can be deployed anywhere SCTP/IP is available π Both tests had connections between Greece and China, and the performance was super satisfactory π¬π·π¨π³ Still, for the FE and CE to work in a non-local environment, an implementor has to make sure the SCTP-TML ports get forwarded to the CE and/or FE if they're behind NATs. If there's a firewall, it has to allow the SCTP ports through π§± These were found during the first ForCES interoperability test and written up in the Implementation Report for Forwarding and Control Element Separation [RFC6053] π
3.3. Model β¨
okay so the ForCES model is literally so dynamic π Using the basic atomic data types that are specified in the model, you can build new atomic (single valued) and/or compound (structures and arrays) datatypes. So developers are free to create their own LFBs π Another iconic perk is inheritance: new versions of existing LFBs can be created to fit any extra developer requirements π¦
The hard part for a developer is building an architecture that is completely scalable, so you never have to rewrite the same code for new LFBs, new components, and so on π The vibe is that developers just write code for the defined atomic values, and then new components get built on top of code that already exists. It's all about reusing it π«Ά
The model itself gives you the key, and the key is inheritance πβ¨
3.3.1. Components
First, a basic component needs to be created as the mother of all the components. It holds the basic parameters that every component has π
- The ID of the component.
- The access rights of the component.
- If it is an optional component.
- If it is of variable size.
- Minimum data size.
- Maximum data size.
If the data size of the component is not variable, then the size is either the minimum or the maximum size, as both should have the same value π
Next up, some basic functions are in order πΈ
- A common constructor.
- A common destructor.
- Retrieve Component ID.
- Retrieve access right property.
- Query if it is an optional component.
- Get Full Data.
- Set Full Data.
- Get Sparse Data.
- Set Sparse Data.
- Del Full Data.
- Del Sparse Data.
- Get Property.
- Set Property.
- Get Value.
- Set Value.
- Del Value.
- Get Data.
- Clone component.
The Get/Set/Del Full Data, Get/Set/Del Sparse Data, and Get/Set Property functions handle the respective ForCES commands and return the respective TLV. For example, Set Full Data should return a RESULT-TLV π The Get Value, Set Value, and Del Value functions get called from Get Full/Sparse Data, Set Full/Sparse Data, and Del Full/Sparse Data respectively. They give you the interface to the actual values in the hardware, which keeps the forces handling logic separate from the interface to the actual values π§
The Get Data function should return the value of the data only, not in TLV format π
The Clone function kinda seems out of place, ngl π This function must return a new component that has the exact same values and attributes. It's useful in array components, as described further below π
The only requirement is to implement the base atomic data types. Any new atomic datatype can be built as a child of a base data type, which will inherit all the functions and, if necessary, override them π¦
Then the struct component can be built. A struct component is a component by itself, but it consists of a number of atomic components. These atomic components create a static array within the struct. The ID of each atomic component is the array's index. For a struct component, the Clone function must create and return an exact copy of the struct component with the same static array π
The most difficult component to build is the array π The difficulty comes from the actual benefit of the model: you have absolute freedom over what you build. An array is an array of components. In all rows, you have the exact same type of component, either a single component or a struct. The struct can have multiple single components, or a combination of single components, structs, arrays, and so on. So the tricky part is how to create a new row, a new component by itself. This is where the Clone function is super useful π For the array, you need a mother component that can spawn new components exactly like itself. Once a Set command is received, the mother component can spawn a new component if the targeted row does not exist, and add it into the array. With the Set Full Data function, the value is set in the recently spawned component, because the spawned component knows how the data is created β¨ To tell these spawned components apart from each other and from their functionality, some kind of index is required. That index will also reflect how the actual data of the specific component is stored on the hardware π₯
Once the basic constructors of all possible components are created, a developer only has to create LFB components or datatypes as a child of one of the already-created components. The only thing the developer really needs to add is the three functions Get Value, Set Value, and Del Value of each component, which are platform dependent. The rest stays the same π
3.3.2. LFBs
The same architecture used for components can be used for the LFBs too, which lets a developer write LFB handling code only once π«Ά The parent LFB has some basic attributes:
- The LFB Class ID.
- The LFB Instance ID.
- An Array of Components.
- An Array of Capabilities.
- An Array of Events.
Following are some common functions:
- Handle Configuration Command.
- Handle Query Command.
- Get Class ID.
- Get Instance ID.
Once these are created, each LFB can inherit all of them from the parent, and the only thing it has to do is add the components that have already been created πΈ
Figure 1 shows an example. The following code creates a part of FEProtocolLFB π
//FEID
cui = new Component_uInt(FEPO_FEID, ACCESS_READ_ONLY, FE_id);
Components[cui->get_ComponentId()]=cui; //Add component to array list
//Current FEHB Policy Value
cub = new Component_uByte(FEPO_FEHBPolicy, ACCESS_READ_WRITE, 0);
Components[cub->get_ComponentId()]=cub; //Add component to array list
//FEIDs for BackupCEs Array
cui = new Component_uInt(0, ACCESS_READ_WRITE, 0);
ca = new Component_Array(FEPO_BackupCEs, ACCESS_READ_WRITE);
ca->AddRow(cui, 1);
ca->AddMotherComponent(cui);
Components[ca->get_ComponentId()]=ca; //Add component to array list
Figure 1: Example Code for Creating Part of FEProtocolLFB
The same concept can be applied to handling LFBs as one FE. An FE is a collection of LFBs. So all LFBs can be stored in an array based on the LFB's class id, version, and instance π§ Then what you need is an LFBHandler that handles the array of LFBs. A specific LFB, for example, can be addressed using the following scheme:
LFBs[ClassID][Version][InstanceID]
Note: While an array can be used in components, capabilities, and events, a hash table or a similar concept is better suited for storing LFBs. Use the component ID as the hash key, with linked lists for collision handling, because the created array can have large gaps if the values of LFB Class ID vary greatly π
3.4. Protocol
3.4.1. TLVs
The goal for protocol handling is to create a general and scalable architecture that handles all protocol messages, instead of something implementation specific π There are some difficulties that have to be overcome first π€
Since the model lets a developer define any LFB required, the protocol gives the user the freedom to configure and query any component, whatever the underlying model. That's a total strength for the protocol itself, but one difficulty is the unknown underlying model and the unlimited number of types of messages that can be created. That makes generic code a daunting task π
The protocol also allows two different path approaches to LFB components, and the CE or FE must handle both, or even a mix of them. That makes generic decoding of the protocol message difficult π
Another difficulty comes from the batching capabilities of the protocol. You can have multiple Operations within a message, and you can select more than one LFB to command and more than one component to manipulate π
A possible solution is, once again, inheritance π¦ There are two basic components in a protocol message:
- The common header.
- The rest of the message.
The rest of the message is divided into Type-Length-Value (TLV) units and, in one case, Index-Length-Value (ILV) units π
The TLV hierarchy can be seen in Figure 2:
Common Header
|
+---------------+---------------+---------------+
| | | |
REDIRECT-TLV LFBselect-TLV ASResult-TLV ASTreason-TLV
|
|
OPER-TLV
|
|
PATH-DATA-TLV ---> Optional KEYINFO-TLV
|
+-------------+-------------+-------------+
| | | |
SPARSEDATA-TLV RESULT-TLV FULLDATA-TLV PATH-DATA-TLV
Figure 2: ForCES TLV Hierarchy
The figure above shows only the basic hierarchical level of TLVs and does not show batching. It also doesn't show the recursion that can happen at the last level of the hierarchy. The figure shows one kind of recursion, with a PATH-DATA-TLV within a PATH-DATA-TLV. A FULLDATA-TLV can be within a FULLDATA-TLV and a SPARSEDATA-TLV. The possible combinations of TLVs are described in detail in the Forwarding and Control Element Separation Protocol [RFC5810], as well as the data-packing rules π
A TLV's main attributes are:
- Type.
- Length.
- Data.
- An array of TLVs.
The array of TLVs is the next hierarchical level of TLVs nested in this TLV π
A TLV's common functions could be:
- A basic constructor.
- A constructor using data from the wire.
- Add a new TLV for next level.
- Get the next TLV of next level.
- Get a specific TLV of next level.
- Replace a TLV of next level.
- Get the Data.
- Get the Length.
- Set the Data.
- Set the Length.
- Set the Type.
- Serialize the header.
- Serialize the TLV to be written on the wire.
All TLVs inherit these functions and attributes, and they either override them or create new ones where it is required β¨
3.4.2. Message Deserialization β¨
Okay bestie, here's the algorithm for deserializing any protocol message π It's basically a step-by-step unpacking routine:
- Get the message header.
- Read the length.
- Check the message type to understand what kind of message this is.
- If the length is larger than the message header, then there is data for this message.
- A check can be made here regarding the message type and the length of the message.
If the message is a Query or Config type, then there are LFBselect-TLVs for this level:
- Read the next 2 shorts(type-length). If the type is an LFBselect-TLV, then the message is valid. π«Ά
- Read the necessary length for this LFBselect-TLV, and create the LFBselect-TLV from the data of the wire.
- Add this LFBselect-TLV to the main header array of LFBselect-TLVs.
- Repeat all above steps until the rest of the message has finished.
The next level of TLVs is OPER-TLVs. π
- Read the next 2 shorts(type-length). If the type is an OPER-TLV, then the message is valid.
- Read the necessary length for this OPER-TLV, and create the OPER-TLV from the data of the wire.
- Add this OPER-TLV to the LFBselect-TLV array of TLVs.
- Do this until the rest of the LFBselect-TLV has finished.
The next level of TLVs is PATH-DATA-TLVs. π¦
- Read the next 2 shorts(type-length). If the type is a PATH-DATA-TLV, then the message is valid.
- Read the necessary length for this PATH-DATA-TLV, and create the PATH-DATA-TLV from the data of the wire.
- Add this PATH-DATA-TLV to the OPER-TLV's array of TLVs.
- Do this until the rest of the OPER-TLV is finished.
Here it gets interesting, as the next level of PATH-DATA-TLVs can be one of the following: π
- PATH-DATA-TLVs.
- FULLDATA-TLV.
- SPARSEDATA-TLV.
- RESULT-TLV.
The solution to this difficulty is recursion π If the next TLV is a PATH-DATA-TLV, then the PATH-DATA-TLV that is created uses the same kind of deserialization until it reaches a FULLDATA-TLV or SPARSEDATA-TLV. There can be only one FULLDATA-TLV or SPARSEDATA-TLV within a PATH-DATA-TLV.
- Read the next 2 shorts(type-length).
- If the Type is a PATH-DATA-TLV, then repeat the previous algorithm but add the PATH-DATA-TLV to this PATH-DATA-TLV's array of TLVs.
- Do this until the rest of the PATH-DATA-TLV is finished.
- If the Type is a FULLDATA-TLV, then create the FULLDATA-TLV from the message and add this to the PATH-DATA-TLV's array of TLVs.
- If the Type is a SPARSEDATA-TLV, then create the SPARSEDATA-TLV from the message and add this to the PATH-DATA-TLV's array of TLVs.
- If the Type is a RESULT-TLV, then create the RESULT-TLV from the message and add this to the PATH-DATA-TLV's array of TLVs.
If the message is a Query, it must not have any kind of data inside the PATH-DATA-TLV. π
If the message is a Query Response, then it must have either a RESULT-TLV or a FULLDATA-TLV.
If the message is a Config, it must contain either a FULLDATA-TLV or a SPARSEDATA-TLV.
If the message is a Config Response, it must contain a RESULT-TLV.
More details regarding message validation can be read in Section 7 of the Forwarding and Control Element Separation Protocol [RFC5810]. π
Note: When deserializing, implementors must take care to ignore padding of TLVs as all must be 32-bit aligned. The length value in TLVs includes the Type and Length (4 bytes) but does not include padding. Don't skip this one, babe π
3.4.3. Message Serialization π§
The same concept can be applied in the message creation process. Having the TLVs ready, a developer can go bottom up. All that is required is the serialization function that will transform the TLV into bytes ready to be transferred on the network. π
For example, for the creation of a simple query from the CE to the FE, all the PATH-DATA-TLVs are created. Then they will be serialized and inserted into an OPER-TLV, which in turn will be serialized and inserted into an LFBselect-TLV. The LFBselect-TLV will then be serialized and entered into the Common Header, which will be passed to the TML to be transported to the FE. That's the whole journey, top to bottom, no cap π
Having an array of TLVs inside a TLV that is next in the TLV hierarchy allows the developer to insert any number of next-level TLVs, thus creating any kind of message. π
Note: When the TLV is serialized to be written on the wire, implementors must take care to include padding to TLVs as all must be 32-bit aligned.
4. Development Platforms πΈ
Any development platform that can support the SCTP TML and the TML of the developer's choosing is available for use. Lowkey so flexible π₯°
Figure 3 provides an initial survey of SCTP support for C/C++ and Java at the present time.
/-------------+-------------+-------------+-------------\
|\ Platform | | | |
| ----------\ | Windows | Linux | Solaris |
| Language \| | | |
+-------------+-------------+-------------+-------------+
| | | | |
| C/C++ | Supported | Supported | Supported |
| | | | |
+-------------+-------------+-------------+-------------+
| | Limited | | |
| Java | Third Party | Supported | Supported |
| | Not from SUN| | |
\-------------+-------------+-------------+-------------/
Figure 3: SCTP Support on Operating Systems
A developer should be aware of some limitations regarding Java implementations. β οΈ
Java inherently does not support unsigned types. A workaround can be found in the creation of classes that do the translation of unsigned types to Java types. The problem is that the unsigned long cannot be used as-is in the Java platform. The proposed set of classes can be found in [JavaUnsignedTypes]. π
5. Acknowledgements π
The authors would like to thank Adrian Farrel for sponsoring this document and Jamal Hadi Salim for discussions that made this document better. Big thanks, the real MVPs π
6. Security Considerations π
Developers of ForCES FEs and CEs must take the Security Considerations of the Forwarding and Control Element Separation Framework [RFC3746] and the Forwarding and Control Element Separation Protocol [RFC5810] into account. This is serious, bestie, do not skip it π
Also, as specified in the Security Considerations section of the SCTP-Based Transport Mapping Layer (TML) for the Forwarding and Control Element Separation Protocol [RFC5811], transport-level security has to be ensured by IPsec. π‘οΈ IPsec is the bodyguard here, no debate π€
7. References π
7.1. Normative References
[RFC5810] Doria, A., Hadi Salim, J., Haas, R., Khosravi, H., Wang,
W., Dong, L., Gopal, R., and J. Halpern, "Forwarding and
Control Element Separation (ForCES) Protocol
Specification", RFC 5810, March 2010.
[RFC5811] Hadi Salim, J. and K. Ogawa, "SCTP-Based Transport Mapping
Layer (TML) for the Forwarding and Control Element
Separation (ForCES) Protocol", RFC 5811, March 2010.
[RFC5812] Halpern, J. and J. Hadi Salim, "Forwarding and Control
Element Separation (ForCES) Forwarding Element Model",
RFC 5812, March 2010.
[RFC6041] Crouch, A., Khosravi, H., Doria, A., Wang, X., and K.
Ogawa, "Forwarding and Control Element Separation (ForCES)
Applicability Statement", RFC 6041, October 2010.
[RFC6053] Haleplidis, E., Ogawa, K., Wang, W., and J. Hadi Salim,
"Implementation Report for Forwarding and Control Element
Separation (ForCES)", RFC 6053, November 2010.
7.2. Informative References
[JavaUnsignedTypes]
"Java Unsigned Types",
<http://nam.ece.upatras.gr/index.php?q=node/44>.
[RFC3654] Khosravi, H. and T. Anderson, "Requirements for Separation
of IP Control and Forwarding", RFC 3654, November 2003.
[RFC3746] Yang, L., Dantu, R., Anderson, T., and R. Gopal,
"Forwarding and Control Element Separation (ForCES)
Framework", RFC 3746, April 2004.
Authors' Addresses π¦
Evangelos Haleplidis
University of Patras
Department of Electrical & Computer Engineering
Patras 26500
Greece
EMail: ehalep@ece.upatras.gr
Odysseas Koufopavlou
University of Patras
Department of Electrical & Computer Engineering
Patras 26500
Greece
EMail: odysseas@ece.upatras.gr
Spyros Denazis
University of Patras
Department of Electrical & Computer Engineering
Patras 26500
Greece
EMail: sdena@upatras.gr
That's the whole RFC, bestie! πβ¨π
π¦ where this page comes from
- ietf: rfc6369 2011-09
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms