Communicating with Tags¶
Overview¶
Modules often exchange information by sending packets along with supplementary data, referred to as tags. A tag is usually a small data structure that focuses on a single aspect of a protocol’s parameterization. Tags can be attached to the whole packet, known as packet tags, or to specific parts of the packet, known as region tags. Tags are implemented as C++ classes that serve as data containers and are usually generated by the OMNeT++ MSG compiler. The primary types of tags are as follows:
Requests carry information from higher layers to lower layers (e.g.,
MacAddressReq).Indications carry information from lower layers to higher layers (e.g.,
InterfaceInd).Plain tags contain meta-information (e.g.,
PacketProtocolTag).Base classes must not be attached to packets (e.g.,
TagBase).
For example, a request tag that specifies the source and destination MAC address could be implemented in an MSG file as shown below:
class MacAddressReq extends TagBase
{
MacAddress srcAddress; // may be unspecified
MacAddress destAddress; // always specified
}
The following is a short description of several commonly used packet tags:
PacketProtcolTag: Specifies the protocol of the packet’s contents.DispatchProtocolReq: Specifies the receiver protocol module inside the network node.EncapsulationProcotolReq: Specifies the requested protocol header encapsulation order.SocketReq: Specifies the application socket.L4PortReq: Specifies the source and destination ports.L3AddressReq: Specifies source and destination network addresses.InterfaceReq: Specifies the outgoing network interface.NextHopAddressReq: Specifies the next-hop address for packet routing.VlanReq: Specifies the virtual LAN identifier of IEEE 802.1Q.PcpReq: Specifies the priority code point of IEEE 802.1Q.StreamReq: Specifies the TSN stream identifier inside the network node.MacAddressReq: Specifies source and destination MAC addresses.Ieee80211ModeReq: Specifies the IEEE 802.11 PHY mode.Ieee80211ChannelReq: Specifies the IEEE 802.11 channel.SignalPowerReq: Specifies transmit signal power.
All request tags have their corresponding indication tags. For example, there
are indications such as SocketInd, InterfaceInd, and StreamInd.
The requests are usually attached to outgoing packets, while the indications are
usually attached to incoming packets.
The following is a short description of several commonly used region tags:
IdentityTag: Uniquely identifies individual bits in the network over the lifetime of the whole simulation.CreationTimeTag: Specifies the creation time of data regions for lifetime measurements.FlowTag: Specifies the packet flows of data regions for various flow-specific measurements.PacketEventTag: Carries information about queueing, processing, transmission, etc. events that happened to data regions.
Communicating Through Protocol Layers¶
Tags can pass through protocol modules, potentially reaching far beyond the module that initially attached them, in both the downward and upward directions. Typically, tags are removed at the point where they are processed, either by being transformed into header fields within a packet or used for some protocol-specific decision-making. Protocols have the freedom to disregard any tags based on their configuration and state.
Both packet tags and region tags usually remain unchanged for many operations that protocol modules carry out with packets. For example, when packets are enqueued/dequeued, encapsulated/decapsulated, cloned, buffered, or stored for later reuse, the tags remain unchanged.
Specifying the Protocol of a Packet¶
The most important packet tag is the PacketProtocolTag. It specifies the
outermost protocol of the packet. This tag should always be present because the
packet protocol cannot be correctly determined just by looking at the raw data.
In contrast, the inner protocol headers in the packet can usually be recursively
identified by protocol fields such as the protocol ID field of the IPv4 header.
The PacketProtocolTag is used, among other things:
- for dissecting the packet along the protocol headers,
- for printing the packet as a human-readable string to help interpret its contents.
Normally, a packet is transformed from one protocol to another in a single step,
so the packet protocol tag either specifies the protocol before the operation
or the protocol after the operation. For example, the Udp protocol module
encapsulates the outgoing packet using a UdpHeader. The packet protocol
is set to an application-specific protocol before the UDP encapsulation, and it’s
set to the UDP protocol after the encapsulation.
Sometimes, protocol implementations themselves are split up into several smaller modules. For example, the modular Ethernet implementation uses a separate module for the insertion of the Ethernet MAC header and the Ethernet FCS. In such a case, the packet protocol tag can only specify the inner protocol that is being encapsulated into an Ethernet MAC frame.
Dispatching Packets to Protocol Modules¶
Inside a network node, protocol modules interact with one another by sending
Packet or Message objects. INET provides great flexibility in terms
of how the protocol modules can be connected. Protocols can be connected directly
to each other or they can be connected through one or more MessageDispatcher
modules. This flexibility allows for the creation of simple as well as complex
network node architectures.
How to Connect Protocol Modules¶
Simple network nodes can be constructed using a linear protocol stack, where protocol modules are directly connected to one another without using message dispatcher modules.
Simple network node structure in the IDE¶
More complex network nodes can be created by grouping protocols into layers and connecting them through MessageDispatcher modules, which facilitate many-to-one and many-to-many relationships among the protocols of the layers.
Complex network node structure in Qtenv¶
It’s also possible to use message dispatcher modules hierarchically within multiple levels of nested compound modules. Ultimately, one could even connect all protocols to a single central message dispatcher module. However, please note that only one instance of a given protocol module can be connected to a message dispatcher.
To support the packet dispatching mechanism, certain additional requirements must be met in the C++ code:
Protocols must be registered using the
registerProtocolfunction.Packets must have the
DispatchProtocolReqtags attached.
Registering Protocols¶
Protocol modules must call the registerProtocol function from the initialize method to inform connected MessageDispatcher
modules of their presence. The following code fragment demonstrates this for the
IPv4 protocol implementation:
void Ipv4::initialize(int stage)
{
if (stage == INITSTAGE_NETWORK_LAYER) {
registerService(Protocol::ipv4, gate("transportIn"), gate("transportOut"));
registerProtocol(Protocol::ipv4, gate("queueOut"), gate("queueIn"));
}
}
Registering the protocols allows the dispatcher modules to learn which gates the protocol modules are connected to. The same protocol is not allowed to be registered in the same message dispatcher using different gates because that would make the dispatching mechanism ambiguous.
Sending Packets with Dispatch Request¶
In order for the message dispatcher modules to correctly dispatch packets to
the intended recipient within the network node, packets and messages must have
the DispatchProtocolReq tag attached. The following example shows how
a MAC protocol could send up a packet to the Ipv4 protocol module without
actually knowing where that module is connected in the network node architecture:
void Mac::sendUp(Packet *packet)
{
auto req = packet->addTagIfAbsent<DispatchProtocolReq>();
req->setProtocol(&Protocol::ipv4); // set destination protocol
req->setServicePrimitive(SP_INDICATION); // determine receiving gate
send(packet, "upperLayerOut");
}
The DispatchProtocolReq tag specifies both the intended recipient protocol
and the requested service primitive. The service primitive, similarly to OSI
terminology, can be one of the following:
SP_REQUESTfor service requests from layer N+1 to layer NSP_CONFIRMfor service confirmations from layer N to layer N+1SP_INDICATIONfor protocol indications from layer N to layer N+1SP_RESPONSEfor protocol response from layer N+1 to layer N
Currently, INET modules only use the SP_REQUEST and SP_INDICATION
service primitives; the other two are only present for completeness. The request
service primitive is used when a higher layer protocol module (e.g., Tcp)
wants to deliver a packet to a lower layer protocol module (e.g., Ipv4).
Similarly, the SP_INDICATION service primitive is used when a lower layer
protocol module (e.g., Ethernet) wants to deliver a packet to a higher layer
protocol module (e.g., Ipv4).
Determining the Next Protocol¶
A protocol module has several options for determining which protocol to forward a packet to. Some possibilities include:
Hard-coding the next protocol in C++. For example, the UDP protocol is hard-coded in C++ in the
UdpSocketclass, and similarly, other protocols are also hard-coded in other protocol-specific sockets.Specifying the next protocol using a module parameter. For instance, a network interface module can specify its expected protocol. The Ipv4 module uses this information to dispatch a packet to the expected protocol of the selected route’s network interface.
Determining the next protocol based on module state. For example, the TSN stream encoder module forwards packets that match the TSN stream mapping to the 802.1 Q-TAG protocol for encapsulation.
Determining the next protocol based on a packet header field. The Ipv4 module, for example, uses the IP protocol ID header field from the
Ipv4Headerto look up the next protocol, as shown below:const Protocol *Ipv4::getNextProtocol(Packet *packet) { auto ipv4Header = packet->peekAtFront<Ipv4Header>(); auto ipProtocolId = ipv4Header->getProtocolId(); return ProtocolGroup::getIpProtocolGroup()->getProtocol(ipProtocolId); }
Determining the next protocol based on packet metadata. For instance, the Tcp module uses the type of the destination address from the
L3AddressReqtag to determine whether the packet should be sent to the Ipv4 or Ipv6 module.Indirectly specifying the next protocol via a protocol encapsulation request. Other modules may have attached an
EncapsulationProtocolReqto the packet in an earlier stage of the packet processing.
Controlling the Packet Encapsulation Order¶
A packet typically contains multiple protocol-specific headers, such as TCP, IP, Ethernet, and sometimes additional optional headers like 802.1Q, 802.1R, 802.1AE, and others. The order of the packet headers is determined by the order in which the packet reaches the relevant protocol modules for encapsulation.
The encapsulation process may need to be different for each packet. For example,
an application may need to send a packet to a specific VLAN. In this case, the
application should attach a VlanReq tag to the packet with the desired
VLAN ID. However, it cannot directly send the packet to the relevant 802.1Q
protocol module because the packet may need to be delivered to the UDP protocol
first. To achieve the desired protocol encapsulation order, the application should
also attach an EncapsulationProtocolReq tag that specifies that the packet
should ultimately be delivered to the 802.1Q protocol for encapsulation. The
underlying protocol modules will use this information to determine when the
802.1Q encapsulation should take place.
The EncapsulationProtocolReq generally outlines the sequence of protocol
modules that a packet should be delivered to for further encapsulation. Additional
tags attached to the packet are used as additional parameters for the requested
processing steps. The attached encapsulation request may be changed several times
during packet processing; new protocols may be added, already added protocols
may be removed, etc.
For example, the IP protocol determines the outgoing interface using the routing
table and the destination address. The selected network interface specifies the
expected protocol that the packet should have in order for the interface module
to operate properly. The specified protocol is appended to the end of the requested
encapsulation protocols of the packet because it should be the last encapsulation
before the packet reaches the network interface. For example, if the IP module
selects an Ethernet network interface, then it appends the Ethernet MAC protocol
to the EncapsulationProtocolReq. As a result, the packet is ultimately encapsulated
into an EthernetMacHeader before reaching the network interface module.
Transforming Inbound Packets to Outbound¶
As part of the forwarding process of Ethernet switches, an inbound packet is transformed into an outbound packet. By default, this process is carried out by the PacketDirectionReverser module. The transformation is more like a policy and can be replaced by the user with other modules. The default module doesn’t change the packet contents, except for removing the already popped front and back parts. However, it changes the attached packet tags significantly.
The inbound packet usually contains a few tags such as PacketProtocolTag
and DirectionTag, and it also contains several indications such as the
InterfaceInd, MacAddressInd, VlandInd, PcpInd,
EncapsulationProtocolInd, etc. During the transformation, only the
PacketProtocolTag is kept, and all attached indications are removed.
Additionally, a set of requests is attached to the packet so that the packet will
be encapsulated in the same protocol headers and sent out on the same interface as it came in.
Of course, this is just the start of the processing of the outbound packet. During the several steps that follow, any of the attached requests can be replaced with new ones, potentially resulting in the packet being handled in a completely different way.