What's New
What's New
# What's New in Simu5G
## v1.8.0 (2026-10-07)
The most significant change in this release is the support for new PDU
session types: besides IPv4, a UE can now have an IPv6, IPv4v6, Ethernet or
Unstructured session, carried end to end from the UE to the data network.
The control plane was rebuilt after 3GPP's division of responsibilities,
with a core network control module and control-plane entry points in the
base stations, UEs and user plane nodes. GTP-U tunnels now carry
per-session TEIDs and, in a 5G core, the QFI. Header compression is
modeled as ROHC configured per bearer. This release, like all releases
since v1.3.1, was developed by Andras Varga and the OMNeT++ core team.
This release requires INET-4.7.0 and OMNeT++ 6.4.0.
### Session types: the UE's sessionType parameter
The session type is the UE's request, as in 3GPP: the PDU session type of
the PDU Session Establishment Request in a 5G core, or the PDN type in an
EPC. The new `LteUe` parameter `sessionType` takes `"IPv4"` (the default),
`"IPv6"`, `"IPv4v6"`, `"Ethernet"` or `"Unstructured"`. The request travels
with the UE's attach to `CoreControl`, which establishes the session with
that type. Every node that ends one of the session's tunnels keeps the type,
so the user plane dispatches on the type instead of parsing packets. An EPC
(a `PgwStandard` anchor) carries the IP types only, and a non-IP session
anchored at a PGW is an error.
**One session per UE.** In 3GPP a UE may have several PDU sessions at once, e.g.
an IPv4 session to the Internet and an Ethernet session to an industrial LAN,
each with its own type, anchor and bearers. In Simu5G a UE has exactly one,
whose type is selected by its `sessionType` parameter. This is a deliberate
simplification that keeps configuration simple: one parameter per UE, and no
session reference in the bearer definitions. Future releases may lift this
limitation and offer an alternative configurator that allows multiple sessions
per UE at the cost of requiring more complex configuration.
Bearers are typed by the session of their UE, so the bearer definitions no
longer carry a type. The `pduSessionType` and `upperProtocol` fields of
`staticDrbs`, `onDemandDrbs` and `drbProfiles` are gone. A definition that
still has one is an error that names the UE parameter. In v1.7.0 only the
default `"IPv4"` worked, so in practice the fields can simply be deleted.
The UE passes the session type to its NIC as well, so the `cellularNic` of
`LteUe` is now typed by the new `IUeCellularNic` interface: an `ICellularNic`
with a `sessionType` parameter. The built-in UE NICs implement it; a custom UE
NIC must implement it too.
### IPv6 and IPv4v6 sessions
- The user plane is address-family neutral. The `Binder` maps `L3Address`es
to node ids. A UE's addresses are registered by the UE RRC's `Registration`
submodule, which follows the cellular interface's configuration as it
changes during the run: link-local and autoconfigured IPv6 addresses
appear only after initialization. On an IPv4v6 session, IPv4 and IPv6
datagrams share the session's bearers, and each goes up as its own
protocol.
- **Neighbor Discovery at the anchor**: in a 5G core, the IP link of an IPv6
session runs between the UE and its anchor UPF (TS 23.502). The new
`Ipv6NdResponder` module, present in `Upf` and `PgwStandard` when
`hasNdResponder = true` (default false), answers the UE's Router
Solicitations with a Router Advertisement that makes it the UE's default
router (`fe80::1` by default). It also answers reachability probes and
consumes duplicate address detection. A UPF without a responder throws when
a UE's link-local IPv6 traffic arrives, instead of leaking it onto the
data network.
- QFI rule filter expressions are evaluated on every packet of their site.
For an IPv6 UE this includes its Neighbor Discovery traffic, so the
examples in the `BearerConfigurator` and `QfiRuleSet` documentation now
guard their expressions with `has(udp)`. For `dscpAsQfi` rules, the DSCP is
also read from the IPv6 Traffic Class field.
- D2D groupcast remains IPv4-only. An IPv6 multicast packet of a D2D-capable
UE goes up the session like that of any other UE.
- Examples: `VoIP-DL-IPv6`, `VoIP-UL-IPv6`, `VoIP-DL-IPv6-Rohc`,
`VoIP-DL-IPv4v6` and `VoIP-UL-IPv4v6` in `nr/standalone`;
`VoIP-DL-MultiQfi-IPv6` and `VoIP-UL-FilterRules-IPv6` in
`nr/standalone_drb`; `CBR-DL-IPv6` in `nr/standalone_multicell`, which
includes handovers; `NeDualConn-VoIP-DL-IPv6` in `nr/dualConnectivity`; and
`SinglePair-UDP-D2D-IPv6` in `lte/d2d`. In these examples the UEs, the
server and the router are IPv6-only, while the transport network (N3, S1-U,
X2) stays IPv4.
### Ethernet sessions
A UE whose `sessionType` is `"Ethernet"` (TS 23.501 5.6.10.2) gets the link
layer of an INET Ethernet node, with the cellular NIC as one of its Ethernet
ports. The UPF switches the session's frames in an Ethernet bridge, among
its Ethernet sessions and its N6 Ethernet LAN.
- **UE**: the new `ethernetMode` parameter selects what the UE is on that
link layer. With `"host"` (the default), the UE is an Ethernet host whose
raw Ethernet applications (e.g. INET's `EthernetSourceApp` and
`EthernetSinkApp`) use the NIC's MAC address. With `"bridge"`, the UE
bridges between the cellular NIC and its `eth[]` interfaces, behind which
further devices can be connected. The 5GS does not carry the FCS: it is
removed on entry and rebuilt on exit.
- **QoS rules** classify a frame by its headers. Their filter expressions
can read the Ethernet MAC header and the 802.1Q C-TAG and S-TAG (PCP, DEI,
VID); a module test documents the accessible fields. A `dscpAsQfi` rule
does not match a frame, and a `dscpAsQfi` rule scoped to an Ethernet UE is
an error.
- **UPF**: the new `EthernetSessionBridge` (submodule `ethBridge`, present
with `hasEthernetBridge = true`) is built on INET's `BridgingLayer`. It
has one port per session, which is created when the session is
established and removed, along with its learned addresses, when the
session is released. Its N6 port is the UPF's `dnEth` interface, which is
connected to the `dnEthg` gate; being the bridge's port, `dnEth` is not an
interface of the UPF's network layer. Traffic between two UEs is switched
at the UPF without passing through N6.
- **Not modeled** (listed in `EthernetSessionBridge`'s documentation):
VLAN-scoped flooding, ARP/ND proxying, allowed VLAN and MAC lists, S-TAG
and C-TAG handling, reporting learned MAC addresses to the SMF, PSA
relocation, and 5G VN groups. IP over an Ethernet session is not
configured automatically.
- **Restrictions**, each an error: an Ethernet session needs a 5G core and an
anchor UPF with an Ethernet bridge, and it is not supported on a
D2D-capable UE or together with ROHC.
- Examples: `simulations/nr/ethernet`, with configs `Ethernet-Hosts`,
`Ethernet-Bridge` (VLAN 42 frames, with PCP 5 mapped to a second QoS flow
and DRB), `Ethernet-Handover` and `Ethernet-Mixed` (Ethernet, IPv4 and
Unstructured UEs at one UPF).
### Unstructured sessions
A UE whose `sessionType` is `"Unstructured"` (TS 23.501 5.6.10.3) sends
opaque payload. The anchor UPF carries it to an application server over the
session's N6 point-to-point tunnel, in UDP/IP datagrams (TS 29.561 9.2).
- **UE**: the new `UnstructuredApp` (and its send-only and receive-only
variants, `UnstructuredSourceApp` and `UnstructuredSinkApp`) attaches to the
cellular NIC directly, as no network layer is involved. A UE has at most
one, in the new `unstructuredApp[]` submodule vector
(`numUnstructuredApps`, default 0).
- **UPF**: the N6 side is configured on the UPF's `nodeControl` module with
the `unstructuredPrefix`, `unstructuredServer`, `unstructuredServerPort`
and `unstructuredPort` parameters. TS 29.561 defines no UDP port for the
tunnel, so the two port parameters have no default. `CoreControl` allocates
an N6 address to each session from the prefix.
- **Restrictions**, each an error: an Unstructured session needs a 5G core
and a UE stack with SDAP, and it has a single QoS flow on the default
bearer. A second bearer, a QoS rule scoped to the UE, reflective QoS, ROHC
and a D2D-capable UE are rejected. MEC steering does not apply, as it goes
by the IP destination.
- Examples: `simulations/nr/unstructured`, with configs `Unstructured`
(with an IPv6 data network, the variant TS 29.561 describes),
`Unstructured-Ipv4N6`, `Unstructured-Handover` and `Unstructured-Mixed`.
### Control plane: CoreControl and the nodes' control-plane entry points
The configuration and signaling that v1.7.0 performed from the
`BearerConfigurator`, the `Binder` and the UE now run between modules that
correspond to the 3GPP entities, as calls named after the messages they
stand for:
- **`CoreControl`** is a new network-level module, next to the `Binder` and
the `BearerConfigurator`. It is the MME and the gateways' control plane of
an EPC, or the AMF and SMF of a 5G core. It establishes and releases the
UEs' sessions and programs the nodes that end their tunnels. It also
delivers the authored QFI rules to their evaluation sites.
- **`ConnectionControlEnb`** is the base station's entry point (submodule
`rrc.connectionControl`). It owns the node's TEID space and its UEs' DRB
identities, establishes their bearers, and runs the network side of
attach, handover and radio link failure. Its D2D variant,
`ConnectionControlEnbD2D`, also establishes the sidelink and multicast
bearers.
- **`ConnectionControlUe`** is the UE's entry point. It is the former
`HandoverController`, which is renamed because it now does more than
handovers: measurements and reports, the execution of a commanded
handover, and attachment and detachment.
- **`UserPlaneNodeControl`** (submodule `nodeControl` of `Upf` and
`PgwStandard`, and so of the MEC host's UPF) is a user plane node's entry
point, the end of N4/S11 at which its sessions are established, modified
and deleted.
- The **`BearerConfigurator`** is now read-only: it holds the bearer
definitions and the QoS rule tables, which are read by the base stations
and by `CoreControl`. The bearer definition schema is unchanged, apart
from the removed `pduSessionType`/`upperProtocol` fields and the new
`rohc` field.
- **Attach**: a UE leg requests an RRC connection from its serving base
station, which registers the UE with the core network (INITIAL UE
MESSAGE). The core network establishes the session and asks the base
station to set up the session's resources: the tunnels, the UE's uplink
QoS rules, and its static bearers. As a consequence, static bearers are
now established UE by UE rather than table entry by table entry. In
networks where several UEs have several static bearers each, this changes
module ids and the order in which results are recorded, but not their
values.
- **Handover**: the UE leg sends its serving base station a
MeasurementReport with the serving and the best cell. The base station
decides through `selectHandoverTarget()`, an overridable policy hook whose
default takes the reported cell, so handovers happen where and when they
did before. The source and the target prepare the handover over Xn
(HANDOVER REQUEST/ACKNOWLEDGE), carrying the leg's context, including its
bearer configuration. The source then commands the UE. When the UE
arrives, the target asks the core network to switch the path (PATH SWITCH
REQUEST) and releases the source (UE CONTEXT RELEASE). The two X2 control
messages that announced a handover and stopped the forwarding are no
longer sent, so the X2 transport's results (SCTP, PPP) change in every
network with handovers.
- **Radio link failure**: the node that detects it informs the peer through
the peer's control-plane entry point, instead of reaching into the peer's
`BearerManagement`.
The signaling is modeled as direct calls: no RRC, NAS, S1AP/NGAP or PFCP
messages are transmitted, a procedure takes no time, and procedures have no
explicit state machines, timers or failure cases.
Networks and configurations written for v1.7.0 need these updates:
- **Declare `CoreControl`**: every network with base stations needs a
`coreControl: CoreControl` submodule next to `binder` and
`bearerConfigurator`. The base stations require it, and initialization
fails without it.
- **Renamed modules**: `HandoverController` is now `ConnectionControlUe`,
`HandoverControllerD2D` is now `ConnectionControlUeD2D`, and
`IHandoverController` is replaced by `IConnectionControl`. In the `Rrc`
compound, `handoverController` and `nrHandoverController` are now
`connectionControl` and `nrConnectionControl`, and their conditions
`hasHandoverController` and `hasNrHandoverController` are now
`hasConnectionControl` and `hasNrConnectionControl`. Ini keys of the form
`**.rrc.handoverController.<param>` must be updated accordingly.
- **Renamed and removed parameters**: `PhyUe`'s `handoverControllerModule`
and `otherHandoverControllerModule` are now `connectionControlModule` and
`otherConnectionControlModule`. The `bearerConfiguratorModule` parameter of
`BearerManagement`, `Ip2Nic`, `NrSdap` and `Registration` is replaced by
`connectionControlModule`, and `TrafficFlowFilter` no longer has one. Also
removed are `GtpUser`'s `ipOutInterface` and `interfaceTableModule`,
`DcMux`'s `binderModule`, `HandoverPacketHolderEnb`'s
`handoverX2ForwarderModule` and `HandoverX2Forwarder`'s
`handoverPacketHolderModule`. All of these have defaults, so only
configurations that override them are affected.
- **C++ API**: the X2 handover control message (`X2HandoverControlMsg`,
`X2HandoverCommandIE`) and the `LteProtocol::ipv4uu` dispatch label are
gone, the `Binder`'s address maps take `L3Address`, and the `Binder` no
longer keeps handover state.
### GTP-U: session tunnels with TEIDs, PDU Session Container, End Marker
In v1.7.0 every GTP-U tunnel carried TEID 0, and each node found the UE of a
datagram from its inner IP address. Now:
- Each UE has a session (session ID 1), anchored at the UPF or PGW where it
was established, for its whole lifetime (SSC mode 1). Each tunnel's TEID
is allocated by its receiving end. Base stations and UPFs identify the
session from the TEID, which also works for non-IP sessions and for IPv6
packets with the unspecified source address.
- The GTP-U header follows TS 29.281. The N3 tunnels of a 5G core carry a
PDU Session Container extension header (TS 38.415) with the QFI, which
makes the header 16 bytes instead of 8. **This changes the results of
every network with N3 traffic towards a UPF.** The header is serialized in
the real format, so the QFI is visible in PCAP recordings and survives
emulation.
- Downlink forwarded over X2 during a handover travels on the target's TEID.
Dual connectivity bearers have per-bearer X2-U tunnels with their own
TEIDs, so PDCP PDUs relayed between the master and the secondary no longer
carry simulation-only metadata across X2.
- At the path switch, the anchor ends the old downlink path with a GTP-U End
Marker (TS 29.281 7.3.2). The source relays it after the downlink it
forwards, and the target holds back the downlink of the new path until the
End Marker arrives (TS 23.502 4.9.1.2.2). Downlink is therefore no longer
reordered at a handover. **This changes the results of every network with
handovers.**
- The base station's user plane is wired directly, as in 3GPP: the cellular
NIC connects to the base station's user plane relay (see below), not to
the base station's own IP layer. Traffic between two UEs of the same base
station is handed straight back to the NIC.
### Header compression (ROHC) configured per bearer
In v1.7.0, header compression was a per-node parameter,
`headerCompressedSize`, which enabled compression on every bearer of the
node and also set the compressed size. In 3GPP it is a per-DRB setting
(TS 38.331 PDCP-Config), normally used only on voice bearers.
- Bearer definitions (`staticDrbs`, `onDemandDrbs`, `drbProfiles`) have a new
`rohc` field: `true` (every modeled profile), `false` (the default), or
`{profiles: [...]}`, which restricts compression to some of the profiles
`"rtp"`, `"udp"`, `"tcp"` and `"ip"`. Each packet is compressed with the
most specific configured profile that fits it, and a packet that no
profile fits is sent uncompressed. IPv6 datagrams are supported.
- **Unidirectional mode (U-mode, RFC 3095)**: each flow has a context. A
bearer has up to 16 contexts (CIDs 0..15), and when they are all taken,
the least recently used one is taken over. A context starts in the IR
state, moves to FO and then to SO, and is periodically refreshed. Header
sizes and transition counts are parameters of the PDCP TX entity
(`rohcSoHeaderSizes`, `rohcFoHeaderSizes`, `rohcIrOverhead`,
`rohcIrPackets`, `rohcFoPackets`, `rohcIrRefresh`, `rohcFoRefresh`), with
defaults taken from the open-source ROHC library. Contexts restart at a
handover. Context damage after losses, O-mode and R-mode, and ROHCv2 are
not modeled.
- **On by default for voice**: the new `BearerConfigurator` parameter
`rohcForDrbProfiles` names the QoS profiles that get ROHC when their
definition does not state `rohc`. Its default, `["5qi-1", "qci-1"]`, turns
compression on for bearers whose definition names the conversational
voice profile. **This changes results for such configurations.** In the
`VoIP-UL-CrossLcg` example, for instance, the mean frame delay drops from
19.46 to 17.54 ms. Bearers that carry voice without naming one of these
profiles are not affected. To restore the previous behavior, set
`rohc: false` on the definition or `rohcForDrbProfiles = []`.
- ROHC applies to IP sessions only. On other session types the policy is
skipped, and an explicitly stated `rohc` is an error.
- **Migration**: setting `headerCompressedSize` is now an error. Use the
`rohc` field instead, and set `rohcSoHeaderSizes` if you need a specific
steady-state size. Unlike v1.7.0, each flow's first packets now carry the
larger IR and FO headers. The unused `LteRohcPdu` message class is
removed; the compressed header is represented by `RohcHeader`.
### The UE is an INET StandardHost
`LteUe`, and with it `NrUe`, `LteCar` and `NrCar`, now extends INET's
`StandardHost`, with the cellular NIC as one more network interface of the
link layer, next to `lo` and the `eth[]` interfaces. The UE used to repeat the
structure of INET's node base modules by hand; it now inherits it, together
with `StandardHost`'s configuration options, and `StandardHost`'s optional
submodules (e.g. `clock`) become available in the UE.
Simulated traffic is unchanged: in the fingerprints, `tplx` and `tNl` are
identical, while `tilx` (module ids) and `sz` (the scalars of the removed
`encap` module) change.
Configurations written for v1.7.0 may need these updates:
- **IP forwarding**: `*.ue.ipv4.forwarding = true` must become
`*.ue.forwarding = true`. `StandardHost` sets its network layers'
`forwarding` from its own parameter, so the old key is silently ignored
rather than rejected. The emulation examples are updated.
- **Radio input gate**: the UE's `radioIn` gate is renamed `lteRadioIn`,
because `StandardHost` already has a `radioIn[]` gate vector (for its
wireless LAN interfaces). The gate receives the air frames by direct
sending and is not connected in networks, so only code that refers to it
by name is affected.
- **`encap` renamed `ethernet`**: the Ethernet encapsulation of the `eth[]`
interfaces (emulation mode) is now `StandardHost`'s `ethernet` submodule,
and it exists only when the UE has `eth[]` interfaces. Parameter settings on
`ue.encap` must address `ue.ethernet` instead.
- **`ethg[]` gates**: the UE now has `ethg[]` gates for its `eth[]`
interfaces, as every INET node does. A network containing a UE with
`eth[]` interfaces whose `ethg[]` gates stay unconnected (e.g. emulation)
must declare `connections allowunconnected`, as INET requires for
`StandardHost`; all emulation examples already do.
- **Interface order and name resolution**: the UE's interfaces are now
registered as `lo0`, the `eth[]` interfaces, then `cellular` (previously
`cellular` came before the `eth[]` interfaces). An address given as the
UE's name, e.g. `destAddress = "ue[0]"`, resolves to the first
non-loopback interface that has an address; for a UE whose `eth[]`
interfaces have IP addresses (emulation), that is now an `eth[]` address,
which the core network cannot deliver to, and the traffic is lost without
an error. Name the cellular interface explicitly in such configurations:
`"ue[0]%cellular"`. UEs without addressed `eth[]` interfaces, which
includes all simulation examples, are unaffected.
### The user plane relay
The nodes that end GTP-U tunnels (`eNodeB`, `gNodeB`, `Upf` and
`PgwStandard`) now have a `relay` submodule, a `UserPlaneRelay`: the "relay"
of the 3GPP user plane protocol stacks, i.e. the `TrafficFlowFilter` that
picks the tunnel and the `GtpUser` that tunnels. The base stations'
`gtpUserX2` stays a submodule of the node. In `Upf` and `PgwStandard`, an
INET `MessageDispatcher` (`rd`) below the relay passes the user data to the
data network interface (`dnPpp`), the Ethernet session bridge or the
Neighbor Discovery responder, by the service it is for.
Configurations and code written for v1.7.0 may need these updates:
- **Submodule paths**: the `gtpUser` and `trafficFlowFilter` of a base
station are now `relay.gtpUser` and `relay.trafficFlowFilter`, and the
`gtp_user` and `trafficFlowFilter` of `Upf` and `PgwStandard` are now
`relay.gtpUser` and `relay.trafficFlowFilter`. Ini keys that address them
must be updated accordingly.
- **Gate names**, named after what the gates carry: `GtpUser`'s
`trafficFlowFilterGate` and `pppGate` are now `userDataIn` and
`userDataOut`, and `TrafficFlowFilter`'s `internetFilterGateIn` and
`gtpUserGateOut` are now `in` and `out`. Only networks that use these
modules outside the Simu5G nodes, and code that refers to the gates by
name, are affected.
### Core network nodes: the N6 interface, and IPv6 on the nodes themselves
- The data-network interface of `Upf` and `PgwStandard` (`dnPpp`) is no
longer in the node's interface table. It belongs to the user plane, which
is wired around the node's network layer, and when the node's own IP stack
routed over it, the result was a crash: at the first IPv6 Neighbor
Discovery message with `hasIpv6 = true`, or at a UPF's own IPv4 traffic
towards the data network. The address configurator no longer assigns
`dnPpp` a subnet, so automatically assigned addresses elsewhere in the
network may be numbered differently. In the examples this affects
`nr/mec/requestResponseApp`, whose results change.
- A base station with `hasIpv6 = true` no longer crashes. Its network layer
sends Neighbor Discovery to the cellular NIC, which is wired to the user
plane rather than to the network layer. As a workaround, the new
`cellularNdSink` (`CellularNicNdSink`) discards these packets.
### Other
- **D2dBinder declared in the network**: a network with D2D-capable nodes
(`hasD2D = true`) must now declare a `d2dBinder: D2dBinder` submodule next
to `binder`. It is no longer created on the fly by the first D2D module that
needs it, and initialization fails without it. The D2D example networks
declare it.
- **Bug fixes**:
- Header compression on a 5G core bearer with a suppressed SDAP header
aborted the simulation at the first packet.
- A handover target built a static bearer without its configuration, so
the bearer lost header compression (causing an abort at the first
downlink packet), its QoS profile and its SDAP QFI mapping. In addition,
an on-demand bearer at the target could take the static bearer's DRB
id. The bearer configuration now travels with the handover context.
On-demand bearers keep their DRB ids across a handover, which swaps
bearer entity names in some results.
- Downlink that the handover source forwarded after the handover had
completed was held at the target indefinitely, i.e. lost.
- UE-to-UE traffic through the core network towards a UE attached
nowhere aborted the simulation; it is now dropped. For an NE-DC
destination UE, such traffic was tunneled to the secondary instead of
the master.
- The QoS-aware scheduler of a base station whose first QoS profiles
arrived after the scheduler's creation never saw any profiles.
- `CbrSender`, `BurstSender` and `VoipSender` waited forever, sending
nothing, when `destAddress` was a literal address, or of the forms
`host(ipv6)` or `host%interface`.
- ROHC treated the payload of a non-first IPv4 fragment as a transport
header.
- X2 handover data was routed to X2 gate 0 by default, which is the CoMP
manager's gate when CoMP is enabled.
- The master eNodeB of the dual-connectivity examples (dualConnectivity,
dualConnectivity_multicell, test_numerology, test_tdd) ran a D2D stack,
although none of their UEs is D2D-capable.
- Serializing an application packet, as PCAP recording, emulation and
computed checksums do, aborted the simulation: `CbrPacket` and
`BurstPacket` had no serializer, and `VoipPacket` could not be
serialized at `VoipSender`'s default packet size of 40 bytes. The VoIP
packet's wire format no longer contains the receiver's arrival and
playout times. In addition, a deserialized `VoipPacket` lost its
timestamp, so `VoipReceiver` computed wrong end-to-end delays in
emulation.
- Memory leaks: the H-ARQ mirror buffers and the conflict graph of the
D2D base station MAC, the per-SDU bookkeeping of the NR RLC AM TX
entity, and the flow descriptor of every RLC RX entity were never
freed.
- **Node layouts**: `LteUe`, `NrUe`, `Upf` and `PgwStandard` are laid out on
INET's node-base grid. The UPF and the PGW are drawn as two stacks: the
core network node's own stack, and the user plane relay with its
data-network interfaces. In `eNodeB` and `gNodeB`, the cellular NIC is
drawn in a box of its own to the right of the node's stack, as it is not
an interface of the node's network layer. The cellular NICs are taller,
with their upper modules in two columns, one per direction.
- **Inspectors**: the runtime state of the modules (counters, tables,
per-UE and per-bearer state) is now `WATCH`ed throughout, so it can be
examined in Qtenv's inspectors. Watches of mere copies of parameters
were removed, and the obsolete `WATCH_MAP`, `WATCH_VECTOR` etc. macros
were replaced by plain `WATCH()`, which displays containers since
OMNeT++ 6.4.
- **Documentation**: the NED documentation was revised throughout. All
parameter and gate comments were reworded where they were unclear, and
wrong ones were fixed (e.g. swapped address and port comments in two MEC
apps). Every example network now describes its topology, and incorrect
3GPP deployment-option claims were removed. The index page now has
starting points for browsing. README, INSTALL and the website were
brought up to date (opp_env as the recommended installation method, the
development history since v1.3), and the website now serves the NED
documentation of the latest release instead of that of v1.3.0.
### Validation
- **Fingerprint tests**: every change was checked against the fingerprint
suite in release and debug mode. The suite grew from 202 to 222
configurations with the IPv6, IPv4v6, ROHC, Ethernet and Unstructured
examples, and with a static bearer that hands over with header
compression. Changes meant to preserve behavior had to leave the
fingerprints unchanged, or, where module ids or the order of
same-instant events moved, to leave `tNl` and the recorded results'
values unchanged.
- **Module tests**: the new `tests/module` suite, modeled on INET's, runs
small simulations and checks their outcome (`make moduletests`). It covers
the configurations a session cannot have, checking both the exit code and
the error message, the frame fields that an Ethernet session's QoS rules
can read, and core networks whose nodes run IPv6. A module test may carry
C++ code, e.g. module classes of its own; the runner compiles it into a
test executable linked with Simu5G and INET.
- **Unit tests**: `RohcCompression` covers profile selection, state
transitions, refreshes and CID allocation. `EthernetSessionBridging`
checks the UPF's bridge against TS 23.501 5.8.2.5.3, one case per sentence
of the spec. VLAN-scoped flooding, which is not modeled, is a recorded
expected failure. `AppPacketSerializers` serializes the packets of the
CBR, burst and VoIP senders at several sizes and checks that they read
back as sent.
### Requires INET 4.7 and OMNeT++ 6.4
Simu5G now requires INET 4.7 and OMNeT++ 6.4; INET 4.5.4 and OMNeT++ 6.3 are no
longer supported. The newer INET is needed for the IPv6 sessions (INET 4.7 has
significantly improved IPv6 support), and the newer OMNeT++ for the newly added
`WATCH`es that display complex data structures. CI builds against INET-4.7.0 and
OMNeT++ 6.4.0, and the fingerprint baselines were re-recorded for them. `tNl`
did not move in any configuration, so the upgrade itself does not affect the
traffic between network nodes.
## v1.7.0 (2026-09-14)
The most significant change in this release is bearer and QoS management, which
now follows the architecture of a real 5G system much more closely: data radio
bearers are described by explicit configuration modeled on the spec's own
records (TS 38.331 bearer configuration, 5QI characteristics, per-direction
QoS-flow classification rules), authored centrally in the new
`BearerConfigurator` module and delivered to the protocol layers that enforce
them. This replaces the implicit on-demand creation of bearers, the packet-name
heuristics and the scattered per-module parameters of earlier releases, and SDAP
is on by default in every network with a 5G core. Dual connectivity gained NE-DC
support, SCG bearers and per-bearer split configuration, and the D2D machinery
moved out of the core LTE/NR stack into a package of its own, behind a `hasD2D`
switch. Buffer status reporting and uplink scheduling moved to the spec's
per-logical-channel-group granularity, which is also what lets the authored QoS
profiles reach the uplink scheduler at all. On the channel model, the 3GPP
propagation formulas were audited against the reports, fixed, covered with unit
tests, and factored into a class family with RAT-neutral names. Changes were
validated using fingerprint, statistical and unit tests (details at the end of
this entry).This release, like all releases since v1.3.1, was developed by
Andras Varga and the OMNeT++ core team.
Tested with INET-4.5.4 and OMNeT++ 6.3, compatible with INET-4.6.0 and
OMNeT++ 6.1 through 6.4.
### Bearer configuration centralized: the BearerConfigurator module
Every data radio bearer is now described by an entry in the tables of
`BearerConfigurator`, a new module that exists once per cellular network,
alongside the `Binder`. It combines, in one network-wide service, decisions
that a real system distributes between the core network and the RAN (in 5GS,
the SMF controls sessions and QoS flows while the NG-RAN maps flows onto
DRBs; in EPS, the roles are spread across the MME and the eNB); the
signaling that would carry the configuration is not modeled, and within the
model the RAN never authors a bearer of its own.
- **`staticDrbs`** is the network's bearer configuration: one entry per
bearer per UE, modeled on the DRB-ToAddMod and RLC-BearerConfig records of
TS 38.331. A static bearer is configured and established up front, in the
last initialization stage, so traffic finds it in place. Entries name
their UE by module path (patterns allowed, so one entry can describe a
bearer of many UEs), and the configuration follows the UE from cell to
cell.
- **`onDemandDrbs`** describes bearers created when traffic first matches
them. An on-demand bearer's properties always come from its definition
entry, never from the packet that triggers it, and a flow that no
definition covers is a configuration error. The parameter's default value
keeps unauthored configurations working: it carries the well-known
packet-name classes (`VoIP*`, `gaming*`, `VoD*`) as ordinary catch-all
definitions for SDAP-less stacks, and a single header-suppressed default
DRB for stacks with SDAP.
- An entry states its architecture with the required **`coreNetwork`**
field: a `"5gc"` bearer is selected by the QFIs mapped onto it
(`mappedQfis`; needs SDAP in the stack), an `"epc"` bearer by packet
filters (`filters`, each an `inet::PacketFilter` -- a message-name pattern
or an `expr(...)` expression). Further fields include the QoS profile of
the bearer's flows (`gbr`, `packetDelayBudget`, `packetErrorRate`,
`qosPriorityLevel` -- 5QI characteristics, pushed into the eNB/gNB MAC for
QoS-aware scheduling), `rlcMode` and `lcg`, `pduSessionType`, `isDefault`,
`suppressSdapHeader`, and the dual-connectivity fields described below.
See the `BearerConfigurator` NED documentation for the full schema and the
modeling abstractions.
- **`drbProfiles`** allows named bearer profiles to be defined: a profile
groups field values (QoS characteristics, `rlcMode`, and so on) under a
name, and an entry that references it via its `profile` field need not
spell those fields out itself -- the profile supplies defaults for the
fields the entry does not state. A commonly used subset of the
standardized QoS characteristics rows is predefined: `"qci-1"`..`"qci-9"`
(TS 23.203) and `"5qi-1"`..`"5qi-9"` (TS 23.501) can be referenced without
being defined. A row carries what the spec standardizes and nothing else.
- The RLC mode and the logical channel group are RAN choices **derived from
the QoS profile** when a definition does not state them: a packet error
rate at or below `amPerThreshold` gets RLC AM (a PER target that HARQ
alone cannot meet gets ARQ), and the priority level is bucketed into an
LCG by `lcgPriorityBounds`.
- DRB identities moved to the 3GPP range: **`drbId` is 1..32** (TS 38.331
DRB-Identity).
- D2D and multicast bearers are outside the definition system: they are
sidelink bearers, whereas the tables describe infrastructure (Uu)
bearers. They are established with a fixed configuration (RLC UM, LCG 3).
This replaces every previous bearer-configuration surface, so
configurations that used one of them need updating:
- **`NrSdap.drbConfig` is gone**; its role is taken by `staticDrbs`. An old
entry like `{"drb": 0, "ue": 2049, "qfiList": [1, 2], "rlcType": "UM"}`
becomes `{coreNetwork: "5gc", ue: "ue[0]", drbId: 1, mappedQfis: [1, 2],
rlcMode: "UM"}` -- the UE is named by module path rather than node id, and
both ends of the bearer are configured from the one entry, so the
two-sided "rlcType must agree" pitfall of v1.6.0 no longer exists.
- **The packet-name traffic classifier is gone.** `Ip2Nic` no longer sorts
packets into conversational/streaming/interactive/background classes; its
`conversationalRlc`, `streamingRlc`, `interactiveRlc` and `backgroundRlc`
parameters no longer exist, and the `LteTrafficClass` enum was removed
(what the scheduler actually consumed all along was the logical channel
group). The old name-based classes survive as the default `onDemandDrbs`
rows, so configurations that relied on the defaults behave as before;
configurations that set the removed parameters state `rlcMode` (and
`lcg`) on bearer definitions or profiles instead.
- Packet-triggered establishment can be disabled with the new
`establishBearersOnDemand` parameter of `NrSdap` / `Ip2Nic`, making the
static configuration the only source of bearers (see the
`VoIP-DL-MultiQfi-NoOnDemand` configuration of `nr/standalone_drb`).
### QoS flow classification: the dlQfiRules and ulQfiRules parameters
Which QoS flow (QFI) a packet belongs to is now authored configuration as
well, once per direction at its ingress: `BearerConfigurator`'s `dlQfiRules`
are delivered to the `TrafficFlowFilter` at each core-network tunnel entry
(modeling the packet detection rules the SMF installs into a UPF), and
`ulQfiRules` to each UE's new `QosFlowClassifier` module (modeling the QoS
rules NAS signaling installs into a UE at PDU session establishment). A rule
matches with an `inet::PacketFilter` and assigns either a fixed `qfi` or the
packet's DSCP field read as the QFI (`dscpAsQfi`); rules are evaluated in
order, first match wins.
Previously the DSCP-as-QFI mapping was hardcoded in `TrafficFlowFilter`, and
at the UE only reflective QoS could assign an uplink QFI. The `dlQfiRules`
default value, `[{dscpAsQfi: true}]`, preserves the old downlink behavior. A
UE-classified uplink QFI now survives to the core network, and the new
`reflectiveQosOverridesQfi` parameter of `NrSdap` arbitrates between a
classified QFI and a reflective QoS match. `NrSdap`'s `useDscpAsQfiFallback`
parameter was removed; a `{dscpAsQfi: true}` rule in `ulQfiRules` expresses
the same policy, authored where the other classification rules live.
### SDAP on by default in 5G standalone networks
`hasSdap`, which used to default to false everywhere, is now derived from
the network's core: every example network built around a `Upf` sets
`**.cellularNic.hasSdap = default(true)` -- the standalone, MEC, cars,
videostreaming and emulation networks all follow. A gNB-served UE in these
networks therefore runs the SDAP sublayer and QFI-based flow-to-DRB mapping,
as a standalone deployment does, and is configured with `"5gc"` bearer
definitions; the EN-DC networks (an LTE core with NR secondaries) remain
deliberately SDAP-less, matching the architecture they model. **Set
`hasSdap = false` explicitly to keep a 5GC-cored simulation on the old
SDAP-less stack.**
Whether a bearer's packets carry the SDAP header on the wire is now a
per-bearer decision (TS 38.331 sdap-HeaderDL/UL), stated with the
`suppressSdapHeader` definition field and verified per packet at the sender:
suppression is only sound while a single QoS flow rides the bearer, and a
second flow showing up stops the simulation with an error instead of
silently mixing flows. The default (unauthored) DRB is header-suppressed, so
turning SDAP on does not by itself change what the example simulations put
on the air -- their re-recorded fingerprints confirm the packet histories
byte-identical -- but the NIC's module structure changes: an `sdap`
submodule and a `qosFlowClassifier` appear.
D2D (sidelink) traffic does not pass through SDAP: SDAP sits between the
core network and the UE, and sidelink flows never touch the core. D2D flows
work identically whether the stack has SDAP or not.
### Dual connectivity: NE-DC, SCG bearers, split-bearer configuration
NE-DC -- dual connectivity with an NR master and an LTE secondary -- now
works end to end. The code had NE-DC in its DC role vocabulary but assumed
an LTE master in several places (per-leg id pairing, UE resolution, leg
steering, the X2 mux keying of secondary-leg uplink PDUs); those now read
the actual technologies off the configuration, and a flow's anchor is the
master's cell group whichever technology that is. The `NeDualConn` example
network moved onto a proper 5GC core, making it the first dual-connectivity
example with SDAP; its new MultiQfi configurations carry SDAP-headered flows
across both legs of a DC bearer.
A bearer definition can now state its dual-connectivity layout:
- **`legs`**: the cell groups that serve the bearer -- one of `"MCG"` /
`"SCG"`, or both for a split bearer (TS 37.340); a leg element can also
override the RLC configuration it inherits from the entry. An SCG bearer's
PDCP still terminates at the master node (an MN-terminated SCG bearer):
the core network delivers the UE's traffic there, and every PDU crosses to
the secondary over X2.
- **`primaryPath`**, **`ulDataSplitThreshold`**, **`ulLegSelection`**,
**`dlLegSelection`**: which leg a split bearer's PDUs take. The uplink
follows the TS 38.323 shape: the UE stays on the primary path until the
amount queued in its legs' RLC buffers reaches the threshold, then uses
both legs -- by default the less-loaded one per PDU, or as the
`ulLegSelection` expression directs. Steering is by buffer occupancy;
previously each packet's leg was decided from its IP type-of-service
marking.
The `TechnologyDecision` module was removed together with the mechanism it
implemented: **IP type-of-service markings no longer influence leg steering
or stack selection**. For a non-DC dual-stack UE, the stack a flow uses
follows from the UE's attachment (the `useNrCondition` parameter, default
`typeOfService >= 10`, is gone); for DC split bearers, steering is the
per-bearer configuration above. Configurations that set
`technologyDecision.typename` or relied on ToS-based selection need
updating.
### Uplink scheduling and buffer status reporting
Buffer status reporting and uplink scheduling were reworked to the
granularity the spec reports at, the logical channel group. Previously the
eNB/gNB kept one aggregate backlog mirror per UE, the two BSR paths
disagreed about what the UE's backlog is, and the QoS-aware scheduler's
uplink half never saw a bearer's QoS profile at all; a UE with uplink
bearers in more than one logical channel group was scheduled badly, and in
the worst case starved.
- **BSRs report per logical channel group** (TS 36.321 / TS 38.321 sec
5.4.5). `MacBsr` carries a per-LCG size array next to the total, and the
eNB keeps one backlog mirror per (UE, LCG) -- the new `UlBacklogRegistry`
-- instead of one per UE, filed under a pseudo-connection with LCID 0. The
uplink scheduler's candidate set carries the per-group pseudo-connections,
so a group is what gets scheduled. MAC control elements occupy no bytes on
the wire, so the finer report costs nothing there.
- **A piggybacked BSR no longer hides the backlog of unscheduled
connections.** The standalone BSR summed all uplink connections, but the
BSR piggybacked on a data PDU summed only the connections in that TTI's
schedule list -- so a connection that scheduling passed over never became
visible to the eNB, which sizes grants from the reported value. Both paths
now compute the report the same way (each connection's occupancy plus, for
a connection with backlog, one RLC header of its mode). In the new
cross-LCG example the lower group's VoIP flows used to deliver 32-37 of
~1000 packets over 20 s, at ~10 s mean frame delay, with ~45% of the
cell's capacity idle -- starvation by invisibility rather than by
priority; they now deliver all of them.
- **An uplink grant is sized from the UE's whole reported backlog.** A grant
is one transport block for the whole UE, which the UE's own LCP then
divides among its channels; it was sized from the mirror of the single
group whose pseudo-connection won the scheduling round, so a UE with
backlog in two groups could never be granted more than the winning group's
worth in a TTI, however idle the cell. With both of its groups loaded, the
cross-LCG example now delivers 13.5% more, and its lower-priority flows go
from 2.3-2.7 s mean frame delay to 33-79 ms.
- **QoS-aware uplink scheduling weighs a group by its bearers' profiles.**
`QOS_PF`'s uplink half looked a pseudo-connection's LCID up as a DRB id,
which no bearer can occupy, so every UE ran at neutral weight (with a
warning per TTI) and authored QoS profiles never reached uplink scheduling
at all. A group's weight now comes from the QoS profiles of the DRBs
established in it, aggregated to the most demanding member on each axis
(lowest priority level, GBR if any, tightest delay budget and error
target).
- **The priority weight no longer depends on the priority scale.**
`QoSAwareScheduler` weighed a bearer by `1/(qosPriorityLevel+1)`, so how
strongly two bearers discriminate depended on the absolute size of their
priority numbers rather than their relation: the same pair of services
weighed 4:3 when authored from the QCI catalog (priorities 2 and 3) and
31:21 from the 5QI catalog (20 and 30). The weight is the pure reciprocal
`1/qosPriorityLevel` now, so only priority ratios matter and the two
catalogs discriminate identically. **`qosPriorityLevel` is also validated
against the 3GPP 1..127 range when the definition is parsed**: an absent
(0) or out-of-range level used to rank a bearer silently above every
legitimate priority. Mixing the two catalogs in one network is still
wrong, because the absolute values drive the `lcgPriorityBounds`
bucketing.
- **Connections of the same LCG are served fairly.** The UE's LCP served the
connections of a logical channel group in registration (that is, bearer
establishment) order, and served each one's entire backlog before looking
at the next -- so of two backlogged same-LCG bearers the first-registered
one took the whole grant, and the other starved at trivial load. A group's
backlogged connections are now served round-robin, one unit per turn (one
virtual-buffer SDU, or one PDU carve in the NR wire format), and the
starting position rotates across TTIs so the granularity bias averages out
instead of always favoring the same connection. LCG index order remains
strict priority. TS 36.321 / TS 38.321 sec 5.4.3.1: logical channels of
equal priority should be served equally.
- The `QOS_PF` proportional quota is computed per node, as its own
documentation says, but was filed under the node's best-scoring
connection, so the node's other connections found no quota and were
granted uncapped. Unreachable while a UE had a single uplink connection,
routine once uplink backlog is tracked per group.
- The fossil two-phase LCP skeleton inherited from SimuLTE was removed from
`LcgScheduler`: an unreachable "switch to best effort" branch, and a token
bucket computed from hardcoded placeholders that nothing ever read. A real
prioritized bit rate remains future work -- this removes the pretense of
one, not the plan for one.
Smaller fixes in the same area: a grant carries the blocks of every codeword
the UE was allocated (dormant today, as uplink allocations are
single-codeword, but it would have gone live with multi-codeword uplink); an
idle D2D connection no longer adds an RLC header to the D2D buffer status
report; the LTE UE's buffer status reports account for RLC header bytes; a
triggered BSR is reported even when the buffers have drained to zero by
reporting time; the standalone BSR the UE main loop schedules is actually
sent; the NR and D2D grant headers are sized in bytes, as plain LTE's are;
and the UE's uplink scheduler clears its scheduled-bytes list each TTI
instead of accumulating an entry per (connection, codeword) for the whole
run. For code that subclasses the MAC: what one connection contributes to a
report is `LteMacUe::computeConnectionBacklog()`, the rule both reporting
paths draw on, and `appendBsr()` returns the size it reported instead of the
caller computing it a second time.
These changes move the results of uplink simulations: measurably wherever a
UE has more than one backlogged uplink bearer, and by design where its
bearers span more than one logical channel group. A simulation whose UEs
each have a single backlogged uplink bearer and no sidelink traffic is
unaffected -- keeping those runs byte-identical was the acceptance test each
of these changes was held to. Five new tests in the `tests/unit` suite pin
the contracts: `QosSchedulerWeight`, `LcgSchedulerFairness`,
`UeBsrReporting`, `EnbUlBacklog` and `EnbGrantFolding`.
### D2D support factored into a separate package
All device-to-device (D2D) code has been moved out of the core LTE/NR stack
into a dedicated `simu5g.stack.d2d` package, and D2D is enabled per node via
a single `hasD2D` switch. The core LTE/NR modules no longer contain any D2D
machinery, and clean (non-D2D) nodes no longer construct it. D2D remains a
research prototype and is not based on any specific 3GPP specification.
- **`hasD2D` node switch.** `LteUe` and `eNodeB` (and, by inheritance,
`NrUe`, `gNodeB`, `LteCar`, `NrCar`) gained a `bool hasD2D =
default(false)` parameter. Setting `**.hasD2D = true` on a node (or a
whole fleet) selects the D2D-capable `cellularNic` variant for that node;
an explicit `cellularNic.typename` still works and takes precedence.
Previously D2D was turned on by naming the D2D NIC type itself
(`*.ue[*].cellularNic.typename = "LteNicUeD2D"`), and the NIC's
`d2dCapable` parameter told the modules inside it which variant they were
in. **That parameter no longer exists**; the node switch has taken over
its role.
- **D2D module types moved to `simu5g.stack.d2d`**, and everything that had
no D2D type of its own gained one -- D2D used to be baked into the plain
`NrNicUe`/`NrNicEnb` and their submodules on the NR side, and into shared
modules such as `RlcMux`, `Ip2Nic`, `LteAmc`, `Rrc` and
`HandoverController` on both. The package holds: NICs `LteNicUeD2D`,
`LteNicEnbD2D` and the new `NrNicUeD2D`, `NrNicEnbD2D`; MACs
`LteMacUeD2D`, `LteMacEnbD2D`, `NrMacUeD2D`, `NrMacGnbD2D`, with the D2D
AMCs `LteAmcD2D`/`NrAmcD2D` and the D2D uplink schedulers; PHYs
`PhyUeD2D`, `PhyEnbD2D` with the `D2dChannelModel`; `RlcMuxD2D` and the
D2D UM entity types; `Ip2NicD2D`; `RrcD2D`, `HandoverControllerD2D`,
`D2DModeController` and the mode-selection policies; and the new
`D2dBinder`, which holds the global D2D state the `Binder` used to.
Module typenames in ini files are unqualified, so these package moves do
not break existing ini files, and most of these types are selected
automatically by the D2D NIC anyway.
- **The D2D parts of RRC live in `RrcD2D`.** The mode controller and the
mode-selection submodule moved out of the core `Rrc` compound into
`RrcD2D`, the subclass the D2D NICs select; core `Rrc` sheds its D2D
wiring, and with it the `hasD2DModeController` switch (a D2D RRC always
has the controller). Switching the periodic mode selection on
(`rrc.hasD2DModeSelection`, set by the D2D eNB/gNB NIC) and choosing its
policy (`cellularNic.rrc.d2dModeSelection.typename`) work as before, so
ini files that select a policy are unaffected.
- **D2D is a project feature** (`Simu5G_D2D`, enabled by default), so Simu5G
can be compiled without the D2D code and examples.
Clean NR nodes no longer construct any D2D machinery, so they no longer run
the periodic mode-selection tick or record D2D statistics -- the `-nan` D2D
scalars that used to appear in non-D2D runs are gone.
### Channel model: the 3GPP propagation formulas audited and fixed
The stochastic channel model's path loss, LOS probability, shadowing and
penetration-loss formulas were audited line by line against the reports they
implement (TR 36.814, TR 36.873, TR 38.901), and the defects found were
fixed. Among others:
- LOS probability: UMa used the UMi formula; RMa's and SMa's exponential
decay constants were swapped; InH lost a 0.54 factor beyond 49 m; and the
TR 38.901 LOS-probability overrides were never dispatched, so the
TR 36.873 formulas ran in their place.
- Path loss: RMa and SMa switched to the post-breakpoint slope at the wrong
distance and evaluated the carrier frequency in the wrong unit; breakpoint
distances now use the 3.0e8 m/s propagation speed the reports define; the
TR 38.901 UMa path never drew the 1 m effective environment height and
missed the tall-UE height draw, and its delegated suburban path aborted,
or dropped the distance.
- Shadowing: several scenarios chose the shadowing sigma with a breakpoint
distance inconsistent with the one their path loss used (or with zero), so
the wrong sigma applied around the breakpoint.
- Building penetration: the O2I model is selected by scenario rather than by
carrier frequency; TR 36.873's is the flat 20 dB the report specifies;
TR 38.901's high- and low-loss models were swapped, and its selector
parameter could never take effect.
Channel state is also keyed correctly now: LOS, shadowing and fading state
belong to a link (a transmitter-receiver pair), not to a node, and the
LOS/shadowing draw is re-anchored each time a link moves a correlation
distance instead of being drawn once per run. D2D receptions are recorded
under the D2D statistics (`rcvdSinrD2D`) instead of the uplink ones, and the
one-to-many (D2D multicast) reception path runs the same SINR and
reception-decision code as everything else.
These fixes change the statistical results of simulations that use the
affected scenarios and models -- in some cases substantially (a swapped
decay constant or penetration model is a many-dB error). To keep the
formulas fixed, they are now covered by tests: the new `tests/unit` suite
grades each implementation against oracle values produced by scripts
transcribed verbatim from the reports, and the new `simulations/channelmodel`
example directory (23 fingerprint configurations) exercises every
propagation formula, both delegation chains, penetration, tall-UE handling,
fading and the sectorial antenna pattern in full simulations.
### Path loss formulas factored into a PathLossModel strategy family
The per-3GPP-study propagation formulas (TR 36.814, TR 36.873, TR 38.901),
previously encoded as inheritance depth in the channel-model class chain, now
live in a stateless strategy class family: `PathLossModel` (abstract) with
concrete `Tr36814PathLossModel` <- `Tr36873PathLossModel` <-
`Tr38901PathLossModel` (the inheritance mirrors each study's own formula
fallback to the previous study, e.g. TR 36.873 has no SMa formulas of its own
and falls back to TR 36.814's). `StochasticChannelModel` owns one strategy
instance and delegates path loss, LOS probability, shadowing and angular
attenuation to it. Which study to use is selected with the new
`pathLossType` string parameter (`"Tr36814"`, `"Tr36873"` or `"Tr38901"`;
default `"Tr36814"`). Everything else -- fading, interference, SINR assembly,
the reception decision -- is unaffected by the choice of study and stays
shared code.
### Channel-model classes and NED types renamed
LteChannelModel -> ChannelModelBase
LteRealisticChannelModel -> StochasticChannelModel
LteDummyChannelModel -> IdealChannelModel
ILteChannelModel -> IChannelModel
NrChannelModel -> Tr36873ChannelModel
NrChannelModel_3GPP38_901 -> Tr38901ChannelModel
The old names implied an LTE/NR split which was never actually there -- any
channel model can serve either an LTE or an NR carrier; what varies is which
3GPP propagation study supplies its formulas, and the new names say so.
`StochasticChannelModel` says how the model works rather than how good it
is: its impairments are drawn from the distributions of a 3GPP propagation
study, as opposed to being computed from the geometry of an actual
environment, and as opposed to the impairment-free `IdealChannelModel`.
`Tr36873ChannelModel` and `Tr38901ChannelModel` are NED-level presets of
`StochasticChannelModel` (no C++ class of their own) that only override the
`pathLossType` default, to `"Tr36873"` and `"Tr38901"` respectively; they are
now named after the propagation study they select, which is the only thing
that distinguishes them. Both extend `StochasticChannelModel` directly -- the
former `NrChannelModel_3GPP38_901 extends NrChannelModel` chain carried no
setting from one preset to the other.
Configurations that name the old NED types explicitly (`@class` overrides,
ini `typename`/`like` selectors, etc.) need to be updated to the new names.
### NIC parameter renamed
`LteNicBase`'s `lteChannelModelType` parameter, which selects the channel-model
NED type plugged into a NIC's `channelModel[]` submodule vector, is renamed to
`channelModelType`. `NrNicUe`'s `nrChannelModelType`, which selects the NR leg
of a dual-leg NIC, keeps its name -- it names a real distinction (the NR leg
of a two-leg NIC), not an accident of the old taxonomy.
Configurations (ini files, NED parameter assignments) that set
`lteChannelModelType` need to rename it to `channelModelType`; the old name
is silently ignored rather than rejected, so a configuration using it stops
taking effect without any error being raised.
### D2D channel math factored into D2dChannelModel
The device-to-device channel math -- D2D RSRP/SINR computation, D2D
interference, and the D2D reception decision -- used to be built into
`LteRealisticChannelModel` itself, so every node's channel model carried it
whether the node had D2D or not. It now lives in `D2dChannelModel`, a
subclass of `StochasticChannelModel` in the D2D package, which is the
channel model of the D2D NICs (their `channelModelType` default) on every
propagation study: the inherited `pathLossType` parameter selects TR
36.814, 36.873 or 38.901 as usual. The `d2dInterference` parameter and the
`rcvdSinrD2D` statistic moved with the code; neither exists on the non-D2D
channel models anymore.
D2D configurations normally need not select a channel model at all: the
D2D NICs default to `D2dChannelModel`, and the study is stated with
`pathLossType`. The core channel models no longer handle D2D
transmissions.
### NrPhyUe removed
`NrPhyUe` was behaviorally identical to `LtePhyUe` (the receive path had
long been unified into the base class); it survived only as a marker class
for the `dynamic_cast<NrPhyUe *>` tests in `HandoverController`, which told
a dual-stack UE apart from a single-stack one -- for which purpose `NrNicUe`
gave BOTH of its legs an `NrPhyUe` (the long-standing "TODO fix this" there).
Those tests now ask the question directly: whether the controller has a
companion-leg `otherHandoverController` to coordinate with. That leaves
nothing for the marker class to do, so it is removed. Both legs of the
dual-stack UE NICs now run the same PHY types as the single-stack ones.
Configurations that name `NrPhyUe` explicitly should select `PhyUe` (see the
rename below) instead.
### PHY classes renamed
The PHY module classes are technology-neutral: both the LTE and the NR leg
of every node run the same classes, with per-leg behavior controlled by the
`isNr` parameter and the channel model plugged into the leg. The `Lte`
prefix is therefore dropped:
ILtePhy -> IPhy
LtePhyBase -> PhyBase
LtePhyUe -> PhyUe
LtePhyEnb -> PhyEnb
LtePhyUeD2D -> PhyUeD2D
LtePhyEnbD2D -> PhyEnbD2D
Submodule names (`phy`, `nrPhy`) and parameters are unchanged, so ini-file
keys are unaffected; only configurations that name the old NED types
explicitly (ini `typename` selectors, `like` clauses, `@class` overrides)
need updating to the new names. The `LtePhyFrameType` enum keeps its name --
it tags frame types and is not a PHY module class.
### Stack opened up for extension
The stack was systematically opened up for external projects that extend
Simu5G by subclassing its modules rather than patching them: some 350
methods across the stack's C++ classes were made virtual (guided by an
explicit rule about what is an extension seam and what is an invariant), the
`Rrc` compound's submodule types became parametric, the layout of a bearer's
legs is overridable, and per-leg identity (the leg's `MacNodeId`, its
gates) is resolved from module parameters instead of hardwired assumptions.
None of this changes behavior; the full fingerprint suite is byte-identical.
### Other
- **Mid-simulation node removal**: a node deleted mid-simulation no longer
leaves state behind that crashes or corrupts the rest of the run: the
`Binder` purges all per-node state when a node is unregistered, RRC tears
down the bearers of a UE deleted mid-run, the AMC forgets D2D feedback
peers that have left the simulation, and a D2D UM TX entity withdraws
from the mode controller before it dies.
- **Handover**: X2-forwarded packets keep their protocol declaration and
their QFI across the forwarding, and a stale QFI-to-DRB mapping left over
from before a handover no longer misroutes flows afterwards.
- **RRC**: dynamic cell association no longer detaches a UE whose
association scan finds no candidate cell. The serving-node lookup in
`Binder::getServingNode()` no longer reads out of bounds.
- **PDCP**: `NrPdcpRxEntity`'s reorder window handles a full drain correctly
(a window that emptied could go out of bounds), and the window shift after
an in-order delivery no longer leaves the last slots stale -- stale slots
matched unrelated sequence numbers, delivered SDUs from the wrong slot and
eventually threw a range check. A new test fills the window to capacity.
- **Errors that stopped runs part-way** are fixed: D2D mode selection
running before the first D2D CQI report threw `std::out_of_range` (the
`SinglePair-modeSwitching-TCP` configurations of `lte/d2d` and `nr/d2d`,
and `FileTransfer-D2D` of `lte/test_handover`, at seed-set 2); the MEC
real-time video receiver stopped the simulation when a segment of an
already-skipped frame arrived late, and now discards it as a real-time
player would (`nr/videostreaming_dataset_generator UrbanNetwork`); and the
`NrPdcpRxEntity` window defect above threw a range check
(`nr/test_numerology MultiCell-CBR-UL`, at seed-sets 1 and 2).
- **Statistics**: the `rlcCellThroughputUl` / `rlcCellThroughputDl`
declarations of `RlcMux` and `macCellThroughputD2D` of `NrMacGnbD2D` are
removed. The cell-level throughput statistics were dropped in v1.6.0
because their value was wrong (each cell reported the network-wide total),
but these declarations came back with the D2D work without an emitter, so
every `.sca` file has carried `-nan` rows for them since. The cell-level
packet-loss statistics (`macCellPacketLossDl` / `Ul` / `D2D`) are live and
unchanged.
- **GtpUser**: locally delivered packets (UE-to-UE within one network) keep
their QFI.
- **D2D multicast**: late joiners of a multicast group get their RX leg, a
remembered multicast flow belongs to its sender rather than just its
group, and the overlapping multicast group ranges in the `nr/cars` example
were fixed.
- **Examples**: `nr/standalone_drb` gained MultiQfi and on-demand-bearer
configurations, `lte/tutorial` an on-demand-bearer configuration,
`NeDualConn` the MultiQfi ones, and a new configuration demonstrates
uplink QoS classification without the applications' cooperation. For the
uplink scheduling work, `nr/standalone_drb` gained `VoIP-UL-CrossLcg` and
`VoIP-UL-CrossLcg-Heavy` (a UE's uplink flows spread over two logical
channel groups, the second with both groups loaded) and `lte/d2d` gained
`OneToMany-UDP-D2D` (one D2D transmitter with four peers, the scenario in
which a D2D buffer status report is built from more than one connection).
- **Tutorials**: `tutorials/nr` set `PacketSize` on its CBR senders, a name
no `CbrSender` parameter has, so the value was ignored and every tutorial
configuration ran with the 40 B default -- a 25x lighter load than the
800 kb/s its comments promise, and than the identical copy under
`simulations/nr/tutorial`. The parameter is spelled `packetSize` now, and
the two run the same simulation.
- **Documentation**: the D2D package and its user-guide chapter, and the
`BearerConfigurator` NED documentation, which describes the full bearer
schema and labels its modeling abstractions honestly -- what is spec, what
is Simu5G policy, and what is not modeled.
### Validation
- **Fingerprint tests**: every change was checked against the fingerprint
suite, which grew from 157 to 202 configurations in this release, now in
two CSVs (`simulations.csv` and `simulations_d2d.csv`, the latter
requiring the D2D project feature), covering the channel-model scenarios
and the new bearer, SDAP, dual-connectivity, cross-LCG uplink and
multi-peer D2D configurations. Changes meant to preserve behavior had to
leave the simulated traffic unchanged, as captured by the fingerprints.
- **Fingerprints are INET/OMNeT++ version specific**: the CSVs hold the
values for INET-4.5.4 + OMNeT++ 6.3.0, the versions CI uses; other
versions report mismatches, and they are expected. Over all 202
configurations: OMNeT++ 6.4.0 moves `sz` in 181 and nothing else, as it
writes the mean of an empty statistic as `nan` rather than `-nan`;
INET-4.6.0 moves `sz` in all of them and `tplx`/`tilx` in 18 and 45; and
INET-4.7.0 is then nearly inert (197 of 202 identical to 4.6.0, the other
five `tplx`/`tilx` only). `tNl` never moves, so the traffic between
network nodes is unaffected by either version; and no combination
produced errors. [This section was added post-release]
- **Statistical tests**: changes that alter behavior were validated by
evaluating how they move the simulation results. The scalar results of
the example simulations are kept as baselines in the
[Simu5G-statistics](https://github.com/inet-framework/Simu5G-statistics)
repository. They were re-recorded at each stage of development (after
every result-changing commit for the uplink scheduling work), and each
deviation was traced to the change that caused it. The repository's
commit history records the effect of each stage on the results.
- **Unit tests**: the new `tests/unit` suite exercises classes directly,
without running a simulation. The path loss, LOS probability, shadowing,
penetration loss and antenna pattern of the 3GPP propagation models are
graded against oracle values computed by a reference script transcribed
verbatim from the reports. The MAC tests pin the QoS scheduler's weight
function, the UE's division of an uplink grant among its connections, the
backlog its buffer status reports announce, and the eNB's per-LCG backlog
tracking and grant construction.
## v1.6.0 (2026-07-31)
This release adds a standards-compliant NR RLC to Simu5G. RLC Unacknowledged
Mode and Acknowledged Mode per TS 38.322 contributed by Esteban Egea Lopez have
been integrated into the mainline and are now the default on NR bearers. The RLC
entity modules were restructured into shared bases with LTE and NR concrete
implementations. The previously incomplete LTE RLC AM was reimplemented per TS
36.322 on the same architecture. Radio link failure detection with RRC
re-establishment was added. This release, like all releases since v1.3.1,
was developed by Andras Varga and the OMNeT++ core team.
Tested with INET-4.5.4 and OMNeT++ 6.3, compatible with INET-4.6.0 and OMNeT++
6.1 through 6.4.
### NR RLC (TS 38.322)
Simu5G's RLC layer so far implemented only the LTE wire format (TS 36.322: FI
framing with concatenation, one sequence number per PDU), and NR bearers used
it as well. This release adds a faithful NR RLC:
- **Unacknowledged Mode**: `NrRlcUmTxEntity`/`NrRlcUmRxEntity` perform SI +
byte-offset (SO) segmentation without concatenation -- one SDU or SDU
segment per PDU, one sequence number per SDU, `NrRlcUmDataPdu` on the wire.
Reassembly is byte-coverage based (`RlcUmReceptionBuffer`) over an SDU-SN
window with `t-Reassembly`. The SN field length is selectable (6 or 12 bits).
- **Acknowledged Mode**: `NrRlcAmTxEntity`/`NrRlcAmRxEntity` perform SO
segmentation with re-segmentation on retransmission (via
`RlcRetransmissionBuffer`), `pollByte`/`pollPDU`-driven status polling
with `t-PollRetransmit`, and reassembly with `t-Reassembly` and
`t-StatusProhibit`, using the `NrRlcAmDataPdu`/`NrRlcAmStatusPdu` formats
over a 12- or 18-bit sequence number window.
- **NR bearers use the NR RLC by default**: `BearerManagement` gained the
`nrRlcUmEntityModuleType` and `nrRlcAmEntityModuleType` parameters (default:
the new `NrRlcUmEntity`/`NrRlcAmEntity` compound modules), and selects them
for every bearer that has an NR node at either end; LTE bearers keep the
`lteRlc*` ones. RLC framing is a function of the RAT rather than a free
choice, so there is no LTE/NR mix; TM, being transparent, is identical for
both RATs and has no NR variant.
This changes results in every NR simulation: the NR wire format has different
per-PDU header sizes and a different segmentation/reassembly discipline than
LTE FI framing, so packet timing, delay and throughput shift. (The MAC and
scheduler groundwork for it -- one PDU per SDU or segment, several RLC PDUs
multiplexed into one grant, exact octet-aligned header sizing -- shipped in
v1.5.1 and is only now actually exercised.) A configuration that needs the
previous behavior can point `nrRlcUmEntityModuleType` and
`nrRlcAmEntityModuleType` back at the `LteRlcUmEntity`/`LteRlcAmEntity`
compounds.
The NR RLC UM and AM implementations were contributed by Esteban Egea Lopez
(Universidad Politécnica de Cartagena). The code was originally published as
the "Simu5G-1.3.1 RLC-AM" special release and rebased onto several Simu5G
versions since; adapting it to the current RLC architecture was done by Attila
Török (OpenSim Ltd).
### RLC entity modules restructured
The RLC entity module and class names were made consistent with their
surroundings (`RlcMux`, `RlcTxEntityBase`, ...), the AM "Queue" names were
normalized to "Entity", and each mode's two variants were factored into a
shared base with LTE and NR concrete subclasses (`RlcUmTxEntityBase` with
`LteRlcUmTxEntity`/`NrRlcUmTxEntity`, and likewise for the other three). The
common shell -- MAC plumbing, D2D mode-switch machinery, UL burst-throughput
accounting -- lives in the base; only buffering, PDU build, reassembly, window
and timer logic is mode-specific. The renames:
UmTxEntity -> LteRlcUmTxEntity TmTxEntity -> RlcTmTxEntity
UmRxEntity -> LteRlcUmRxEntity TmRxEntity -> RlcTmRxEntity
AmTxQueue -> LteRlcAmTxEntity
AmRxQueue -> LteRlcAmRxEntity
Configurations that name these NED types explicitly need to be updated. The
`NrRlcUmEntity` and `NrRlcAmEntity` compounds are subclasses of
`RlcUmEntityBase` and `RlcAmEntityBase` that bind their two sides to the NR
concrete entities with `tx.typename`/`rx.typename`.
### LTE RLC AM reimplemented per TS 36.322
Simu5G's original LTE RLC AM was derived from UMTS RLC (TS 25.322), it was
incomplete, and no simulation configuration used it. What it implemented was not
TS 36.322 compliant: the wire format was per-SDU fragmentation with a sequence
number per fragment (no concatenation, no FI/LI, no poll bit), retransmission
was driven by per-PDU timeouts that resent without any NACK, a PDU exhausting
its retransmissions was silently discarded with no radio link failure
indication, and status reporting was periodic rather than event-driven.
It has been reimplemented from scratch on the architecture of the NR AM
entity, whose TS 38.322 ARQ skeleton TS 36.322 shares; only the framing is
LTE-specific:
- One AMD PDU per MAC grant, built by concatenating queued SDUs and SDU
fragments (FI framing, on the same PDU model the LTE UM entity uses). The
built PDU, retained in the 512-entry (10-bit SN) transmission window, is the
unit of ARQ.
- NACK-driven retransmission with the `ACK_SN` + NACK-list STATUS PDU (the
same `StatusPduData` structure the NR AM uses, including SOstart/SOend byte
ranges), re-segmenting a retained PDU into AMD PDU segments when the grant
is smaller than the PDU.
- `pollPDU`/`pollByte`/`t-PollRetransmit` polling, `t-Reordering` and
`t-StatusProhibit` at the receiver, and radio link failure at
`maxRtxThreshold` retransmissions, wired to the same
`BearerManagement` teardown and RRC re-establishment as the NR AM.
Since no configuration could use the old LTE AM, this does not affect existing
simulation results.
### Selecting RLC AM
Acknowledged Mode is now usable on both RATs, but nothing selects it by default:
every bearer stays in the mode it had before, so existing simulations are
unaffected. Two mechanisms choose the mode of a bearer, depending on whether
SDAP is in the stack.
Without SDAP, `Ip2Nic` classifies each packet into a traffic class by packet name
(`VoIP*` -> conversational, `gaming*` -> interactive, `VoDPacket*` -> streaming,
anything else -> background) and maps the class to an RLC mode with its
`conversationalRlc`, `streamingRlc`, `interactiveRlc` and `backgroundRlc`
parameters. They accept `"TM"`, `"UM"` and `"AM"`, and all four default to
`"UM"` (which is the pre-v1.6.0 behavior, kept for backward compatibility).
With SDAP in the stack (`hasSdap = true` on the NR NIC), `Ip2Nic` skips traffic
classification entirely and the mode becomes a property of the DRB: every entry
of `NrSdap.drbConfig` takes an optional `rlcType` field, again one of `"AM"`,
`"UM"` and `"TM"`, and again defaulting to `"UM"`. For example:
*.gnb.cellularNic.hasSdap = true
*.gnb.cellularNic.sdap.drbConfig = [
{"drb": 0, "ue": 2049, "qfiList": [1, 2], "rlcType": "UM"},
{"drb": 1, "ue": 2049, "qfiList": [3, 4], "rlcType": "AM"}]
Either way, both ends of a bearer must be configured with the same mode: each
node builds its own RLC entity from its own configuration, so a mismatch leaves
an AM entity facing a UM one. With `Ip2Nic`, this can be ensured by using `**.`
wildcards; with SDAP, the UE's `drbConfig` entry for a DRB and the gNB's entry
for the same DRB have to agree on `rlcType`.
Which entity type then implements the mode follows from the RAT, as described
above: an AM bearer with an NR node at either end runs the `NrRlcAmEntity`
compound, an LTE one `LteRlcAmEntity`. TM is available on both, and is the same
entity for both.
### RLC validation scenarios
The new `simulations/nr/rlc` and `simulations/lte/rlc` directories hold
protocol-validation scenarios for the two RLC implementations: a single UE
over `LteDummyChannelModel` -- which replaces propagation modelling with a
configurable per-direction packet error rate, so with independent HARQ
attempts the residual loss RLC sees is exactly `perDl^(maxHarqRtx+1)` -- with
deterministic CBR traffic and the loss process on its own RNG. The scenarios
sweep the error rate (`AM-Lossy`, with `UM-Lossy` as the no-ARQ contrast),
force segmentation and re-segmentation on retransmission (`AM-Segmentation`),
concatenation on LTE (`AM-Concatenation`), a transmission-window stall that
must recover (`AM-WindowStall`), and a scripted mid-run coverage loss that
must end in a radio link failure (`AM-RLF`) or in RRC re-establishment with
the flow resuming (`AM-RLF-Reestablish`). Three scenarios cover the common
usage patterns beyond a lossy downlink: `AM-Lossy-UL` (both RATs) runs the
flow uplink, through the UE MAC's strict grant accounting; `TCP-AM` carries a
TCP transfer over the lossy bearer, its acknowledgement stream putting data
through the reverse direction of the same bearer; and
`lte/test_handover VoIP-AM-Handover` runs bidirectional VoIP over AM with the
UEs moving through handovers.
Measured on both RATs: every AM configuration delivers every offered SDU at
every loss rate in the sweep, uplink and downlink -- the AM guarantee --
while UM loses the predicted residual fraction, and the per-attempt HARQ
error rate matches the configured error rate throughout. TCP makes steady
progress over a downlink losing half its transmission attempts, and the
handover scenario completes with zero application-level frame loss and no
entities left behind at the old cell.
Defects found in the NR AM implementation found using these scenarios
were fixed.
### Radio link failure and RRC re-establishment
The RLC AM transmitters declare a radio link failure when a PDU exceeds
`maxRtxThreshold` retransmissions (TS 38.322 5.3.2 / TS 36.322 5.2.1). This
is now wired to a full teardown of the link:
- `BearerManagement::scheduleRadioLinkFailure()` defers the teardown to a safe
execution context (so that entity modules are never deleted from inside
packet processing), then releases the link at both ends -- reaching the
peer's `BearerManagement` through the `Binder` -- deleting the bearer's MAC
(`deleteQueuesRadioLinkFailure()`, which also drops the node's in-flight HARQ
feedback), RLC and PDCP state.
- `Ip2Nic` gained `releaseUe()`/`resumeUe()`, and drops a released peer's DL
and UL packets for as long as its context is released, modeling the RRC UE
Context Release. Without this, the application kept pushing packets at
torn-down entities, which crashed; handover does not have this problem only
because it redirects the traffic to a new cell.
- RRC re-establishment (TS 38.331 5.3.7) is modeled by its timers, the way
handover signaling already is: `BearerManagement.t311` (cell selection) and
`t301` (request to complete). When `t301` expires, the peer is un-released
and its bearer re-establishes on demand. The default `t311 = 0s` disables
re-establishment, that is, a radio link failure releases the UE to idle.
This is inert in simulations that do not use RLC AM, as only the AM entities
detect radio link failures.
### RLC statistics recorded on the bearer entities
The per-bearer RLC statistics -- `rlcDelay*`, `rlcThroughput*`, `rlcPduDelay*`,
`rlcPduThroughput*`, `rlcPacketLoss*` and their D2D variants -- are now recorded
on the RLC entity module of the bearer that produced them, instead of on an
`RlcMux`. **Configurations and analysis files that refer to these results by
module path need to be updated**, for example from
SingleCell.ue[0].cellularNic.nrRlcMux.rlcDelayDl:mean
to the bearer entity that measured it, such as
SingleCell.ue[0].cellularNic.nrRlc-um-1-1.rx.rlcDelayDl:mean
The old arrangement dates from when RLC was a single module per network
interface, with the per-connection entities being plain C++ objects inside it:
there was no per-bearer module to record on, so a receiving entity reached the
*other* node's mux through the `Binder` and emitted the sample there -- an
uplink measurement taken at the gNB was recorded as a result of the UE. Since
v1.5.0 the entities are modules in their own right, one per peer and radio
bearer, so each sample is now recorded where it is produced. Results for one UE
across its bearers are obtained by aggregating over its entity modules in the
analysis tool.
The cell-level statistics (`rlcCellThroughput*`, `rlcCellPacketLoss*`) were
**removed** rather than moved. The cell throughput was computed from a C++
`static` byte counter -- one counter for the entire simulation, not one per
cell -- so in any scenario with more than one cell, every serving node reported
approximately the network-wide total as its own cell throughput. (In
`lte/multicell`, both eNBs report the global figure; the true per-cell values
are about half of what was recorded.) The statistic was correct only in
single-cell scenarios, where it equals the sum of the per-bearer
`rlcThroughput*` results, which is how it can be obtained now.
The MAC layer's `macCellThroughput*` statistics (including the D2D variant,
which shared the same counter and thus mixed D2D and cellular bytes) had the
identical defect and were removed for the same reason; the per-UE
`macThroughput*` results remain. `macCellPacketLoss*`, which is computed
per-cell correctly, is kept.
Two side effects are worth noting. `rlcPacketLoss*` was emitted onto a module
that did not declare it, so it was never recorded at all; it now is. And
per-bearer results that used to be merged into one mux are visible separately
per bearer, which is what makes the two legs of a Dual Connectivity split
bearer individually measurable.
### PDCP mux renamed and refactored
`UpperMux` was renamed to `PdcpMux`: the old name said where the module sits
relative to the PDCP entities rather than which layer it belongs to, and did not
match its RLC counterpart `RlcMux` (the submodule was already named `pdcpMux`).
Like `RlcMux` in v1.5.2, it now maps DRBs to `toTxEntity` gate indices instead
of TX entity pointers, so dispatch is plain multiplexing.
Both muxes became replaceable submodules, with the new `IPdcpMux` and `IRlcMux`
module interfaces. Replaceability is partial: `BearerManagement` creates and
wires the per-bearer gates and registers the routing tables through the C++
classes, so an implementation has to subclass `PdcpMux` or `RlcMux`; what the
interface buys is type selection from NED and ini.
The NR-leg flag moved off `PdcpMux`, which never read it, onto its only reader,
`Ip2Nic`: **`cellularNic.pdcpMux.isNR` is now `cellularNic.ip2nic.isNr`**,
spelled like the same flag on `LteMacUe`, `LtePhyUe` and `HandoverController`.
Configurations that set it need to be updated. `BaseStationStatsCollector` also
lost its `pdcpModule` parameter, which was unread and pointed at a module the
v1.5.0 PDCP flattening deleted.
### Other
- **RLC statistics on NR bearers**: the NR RLC entities did not emit the
per-bearer delay and throughput statistics that their LTE counterparts do, so
those results were empty in NR simulations from the moment the NR RLC became
the default on NR bearers. They are emitted now. `NrRlcAmRxEntity` also emits
`rxWindowOccupation`, which was declared but never emitted; the NR UM
transmitter's `requestedPDUSize`/`sentPDUSize` statistics were renamed to
`requestedPduSize`/`sentPduSize`, and it gained the
`receivedPacketFromUpperLayer`/`sentPacketToLowerLayer` counters.
- **LteDummyChannelModel made usable**: the class had no NED type (so it could
not be instantiated) and hardcoded error rates. It now has one, with `per` /
`perDl` / `perUl` / `perD2D` and `harqReduction` parameters -- the
per-direction rates volatile, so a coverage loss can be scripted as a
function of time -- turning it into a controlled loss source for protocol
validation: with `harqReduction = 1` the residual loss RLC sees is exactly
`per^(maxHarqRtx+1)`. It also reports SINR/RSRP on every band; the
single-element vector it used to return broke the AMC.
- **MEC RNI**: `PacketFlowObserver` now also tracks NR SO PDUs, which carry no
per-PDU RLC sequence number, by keying the per-SDU tracking on the PDCP
sequence number instead. The reported delay is exact for the common
unsegmented case; an SDU segmented across several MAC PDUs is accounted as
delivered on the acknowledgement of its first segment.
- **D2D**: D2D bearers run on the NR RLC as well; draining of the mode-switch
holding buffer now takes place in the owning entity's context.
- **Module references**: the RLC-to-RRC and RRC-to-Ip2Nic lookups became NED
module-path parameters (`RlcMux.bearerManagementModule`,
`BearerManagement.ip2nicModule`), continuing the `ModuleRefByPar` conversion.
- **Simulations**: `nr/standalone` gained the `VoIP-DL-AM`, `VoIP-DL-AM-Lossy`,
`VoIP-UL-AM`, `VoIP-DL-UM-NR` and `VoIP-UL-UM-NR` configurations, and
`lte/demo` the `VoIP-AM` configuration, exercising the AM and the NR RLC
paths.
- **Fingerprint tests**: the five new configurations above were added to the
suite, together with the RLC validation scenarios of `simulations/nr/rlc`
and `simulations/lte/rlc` and the `VoIP-AM-Handover` configuration of
`lte/test_handover` (157 configurations in total), and the rows were
re-recorded for the NR RLC default and the statistics changes.
- **Documentation**: the RLC entity documentation comments were retargeted at
the compound modules that actually bind them -- several still referred to
per-side `rlcUm{Tx,Rx}EntityModuleType` parameters, which v1.5.1 replaced
with selection on the per-bearer compound -- and the `RlcUmEntityBase` /
`RlcAmEntityBase` comments now name both of their concrete subclasses.
- **Source housekeeping**: file headers were brought in line -- the contributed
NR RLC sources now carry the standard Simu5G header naming their author
instead of an LGPL blurb, files that had no header got one, and new files
that had inherited the header of the file they were derived from now name
their actual author. The redundant `@class` line was dropped from the C++
class comments, and `IRlcAmEntities.ned` was split into `IRlcAmTxEntity.ned`
and `IRlcAmRxEntity.ned`, one interface per file. The interfaces themselves,
and all type names, are unchanged.
## v1.5.2 (2026-07-30)
This release corrects the names of the per-bearer PDCP and RLC entity modules
that v1.5.0 and v1.5.1 introduced, before more code comes to depend on them. It
changes names only: no behavior changes, and no simulation results change. It
also refactors RlcMux.
Tested with INET-4.5.4 and OMNeT++ 6.3, compatible with INET-4.6.0 and OMNeT++
6.1 through 6.4.
### PDCP and RLC entity module names made consistent
The PDCP entity modules and their module interfaces were renamed so that the
TX/RX role follows the layer name, as it does in RLC and in their own C++ base
classes (`PdcpTxEntityBase`, `PdcpRxEntityBase`):
LteTxPdcpEntity -> LtePdcpTxEntity ITxPdcpEntity -> IPdcpTxEntity
LteRxPdcpEntity -> LtePdcpRxEntity IRxPdcpEntity -> IPdcpRxEntity
NrTxPdcpEntity -> NrPdcpTxEntity
NrRxPdcpEntity -> NrPdcpRxEntity
The per-bearer compound modules were restructured so that an explicit LTE
concrete type stands beside the NR one, instead of the base type doubling as the
LTE type. `PdcpEntity`, `RlcUmEntity` and `RlcAmEntity` became `PdcpEntityBase`,
`RlcUmEntityBase` and `RlcAmEntityBase`, which bind no entity types and are
therefore not instantiable on their own; the instantiable types are their
subclasses, which bind their two sides with `tx.typename`/`rx.typename`:
PdcpEntity -> PdcpEntityBase + new LtePdcpEntity
RlcUmEntity -> RlcUmEntityBase + new LteRlcUmEntity
RlcAmEntity -> RlcAmEntityBase + new LteRlcAmEntity
`NrPdcpEntity` is now a subclass of `PdcpEntityBase`. A mixed entity (e.g. an
EN-DC master eNB, which runs an NR TX side with an LTE RX side) still overrides
just `tx.typename` or `rx.typename`.
`BearerManagement`'s parameters that select the RLC entity types were renamed so
that the LTE ones are marked as explicitly as their coming NR counterparts:
`rlcUmEntityModuleType` -> `lteRlcUmEntityModuleType` and
`rlcAmEntityModuleType` -> `lteRlcAmEntityModuleType`. Its
`pdcpEntityModuleType` parameter keeps its name -- it is a single per-node
selector, and it holds an NR type at every gNB -- and now defaults to
`LtePdcpEntity`. `RlcTmEntity` and `rlcTmEntityModuleType` are unchanged: TM is
transparent and identical for both RATs, so it has a single entity type.
Configurations that name any of these NED types explicitly need to be updated.
### RlcMux refactoring
`RlcMux` now maps DRBs to gate indices, not RX entity pointers. Its internal
table now holds the index of the `toRxEntity` gate serving each DRB instead of a
pointer to the RX entity, so PDU dispatch is plain multiplexing: `send()` on the
gate index, with no entity involved. It used to make a round trip -- look up the
entity, then ask it for its gate and walk back to our own gate.
## v1.5.1 (2026-07-28)
This release continues the architectural overhaul of Simu5G, focusing on the
PDCP and RLC layers: per-bearer protocol entities are now packaged into
compound modules, DRBs are established as bidirectional (duplex) bearers, and
the Dual Connectivity split-bearer data path was restructured.
Tested with INET-4.5.4 and OMNeT++ 6.3, compatible with INET-4.6.0 and OMNeT++
6.1 through 6.4.
### Per-bearer PDCP and RLC compound entity modules
v1.5.0 transformed the PDCP and RLC layers into dynamically created per-bearer
TX/RX entity modules. This release packages the two sides of each bearer into
one compound module per bearer, following the 3GPP model of one PDCP/RLC
entity per bearer (for RLC AM explicitly with a transmitting and a receiving
side):
- **RLC**: Each bearer's TX and RX entities now live in an `RlcTmEntity`,
`RlcUmEntity` or `RlcAmEntity` compound module. In AM, the internal control
paths are now explicit gate connections between the RX and TX submodules,
replacing C++ registry-lookup calls between the two simple modules:
`feedbackOut` -> `feedbackIn` carries the STATUS PDUs received from the peer
into the TX side's ARQ, and `statusOut` -> `statusIn` hands the locally
generated status reports to the TX side for transmission.
- **PDCP**: Each bearer's TX and RX entities now live in a `PdcpEntity`
compound module. Variants are subclasses overriding the entity typenames
(`NrPdcpEntity`); a mixed entity (e.g. an EN-DC master eNB, which runs an NR
TX side with an LTE RX side) overrides just `tx.typename` or `rx.typename`.
- **PdcpRelayEntity**: At a Dual Connectivity secondary node, which only
tunnels already-processed PDUs between the master (over X2) and its own RLC,
the two per-bearer bypass modules were packaged into a `PdcpRelayEntity`
compound module, which stands in place of the bearer's PDCP entity;
`BypassTxPdcpEntity`/`BypassRxPdcpEntity` were renamed to
`PdcpDownlinkRelay`/`PdcpUplinkRelay`.
- New module interfaces (`ITxPdcpEntity`, `IRxPdcpEntity`, `IRlcTxEntity`,
`IRlcRxEntity`, `IRlcAmTxEntity`, `IRlcAmRxEntity`) make the entity
implementations replaceable: every compound binds its two sides with the
standard `tx.typename`/`rx.typename` submodule typename assignment, which a
configuration or a subclass of the compound can override. The ten per-side
entity-type parameters of `BearerManagement` were consolidated into five
per-compound ones (`pdcpEntityModuleType`, `pdcpRelayEntityModuleType`,
`rlcTm/Um/AmEntityModuleType`).
### DRBs established as duplex (bidirectional) bearers
Per TS 38.331, a DRB is bidirectional; Simu5G so far established each
direction as an independent unidirectional bearer with its own
locally-assigned DRB id. RLC AM fundamentally needs the reverse path of the
same bearer for its STATUS PDUs, which the old model could only provide via
on-demand reverse entities created from inside packet processing. Now:
- `Binder::establishDataConnection()` (renamed from
`establishUnidirectionalDataConnection()`) creates both directions of a
unicast bearer at once; multicast bearers remain unidirectional.
- DRB ids are allocated by the `Binder` with a counter per node pair, so the
two ends of a bearer see the same DRB id, and DRB ids are peer-scoped
(per-UE identities, as in the spec) rather than node-unique.
- Reverse application traffic resolves to the reverse leg of the existing
bearer instead of allocating a second bearer.
This may change results in simulations where request and response flows
between the same node pair previously used two separate bearers: they now
share one duplex bearer, which changes logical channel ids and can change
scheduling order under contention.
### Dual Connectivity split-bearer data path restructured
A DC split bearer is one PDCP entity -- one sequence number space -- whose
PDUs are steered per-packet across two RLC legs. The `PdcpEntity` compound now
reflects this: its lower boundary is a `legOut[]`/`legIn[]` gate vector. A
plain bearer has one leg, and the TX/RX entities connect straight to it; a
split bearer routes the TX side through a `DcPdcpLegSplitter` (per-PDU leg
dispatch, per-leg DC id mapping and statistics) and merges both legs through a
`PdcpLegJoiner` into the single RX entity, whose one reordering window
restores sequence order across the legs. The per-packet leg steering policy
itself remains in `TechnologyDecision`; the splitter only executes it.
### MAC prepared for NR RLC framing
The MAC and the schedulers can now accommodate an RLC that emits one SDU or
segment per PDU without concatenation (the NR model of TS 38.322), in addition
to LTE's single concatenated PDU per grant: for such flows, the schedulers
plan one PDU per SDU/segment to fill the grant, the MAC issues one SDU request
per planned PDU and multiplexes them into the MAC PDU, and exact per-PDU RLC
header sizes are computed (octet-aligned, per SN length and segment state).
This is inert by default (`soFraming=false` keeps the LTE path) and is
groundwork for an upcoming standards-compliant NR RLC implementation.
### Beacon emission control at the eNB/gNB
- Beacon broadcasting was decoupled from `enableHandover`: the new
`enableBeacons` parameter (default: `enableHandover`) controls it, so that
radio link monitoring can later work without handover enabled.
`enableHandover=true` now requires beacons to actually flow.
- A non-positive `beaconInterval` is now an initialization error instead of
silently disabling beacons; beacons are switched off with
`enableBeacons=false`.
### Module architecture improvements
- **isNr as parameter**: `LteMacUe`, `LtePhyUe` and `LteDlFeedbackGenerator`
no longer determine whether they are the NR leg of the UE by string-matching
their own module name ("nrMac", "nrPhy", "nrDlFbGen"); they now have a
`bool isNr` parameter, set by `NrNicUe`.
- **Parametrized module references**: Hardcoded `getSubmodule()` walks inside
the NIC were replaced with NED module-path parameters (11 new parameters
across `BearerManagement`, `HandoverController`, `DcMux`, `LteMacEnb` and
`TechnologyDecision`), and foreign-node lookups now go through `Binder`
helper methods.
- **IHandoverPacketHolder**: The `hoManagerOut` gate was added to the module
interface, so that custom holder implementations can be substituted
(contributed by Mohamed Seliem).
### Bug fixes
- **Crash on interleaved Dual Connectivity leg handovers**: Fixed a
long-standing crash (also present in v1.4.3..v1.4.5) triggered when the LTE
leg of an NR UE hands over while its NR leg is detached: per-UE state
provisioned at the old master's secondary gNB was left orphaned, and
re-establishment collided with the leftovers when the UE later returned.
Handover cleanup now also covers the old serving node's secondary. In
addition, PDCP entity teardown at NR UEs is now keyed by peer node, so an
NR-leg detach no longer deletes the LTE leg's entities as well.
- **MAC**: `macSduRequest()` no longer underflows when the scheduler allocates
a grant smaller than the MAC header, which surfaced as a misleading
"configured queueSize too low" error with many DRBs under `QOS_PF`
contention (contributed by Mohamed Seliem).
- **NrPhyUe**: D2D DATA frames arriving while the UE is detached during
handover are now dropped, as `LtePhyUeD2D` already did, instead of crashing
on already-deleted HARQ buffers.
- **HandoverController**: Removed a redundant second detach/attach of the D2D
direction on the AMC during NR UE handover.
- **LtePhyEnb**: Corrected copy-pasted class names in `requestFeedback()`
error messages.
### Other
- **Fingerprint tests**: The simulation-time intervals of configurations
involving events like handover or D2D mode switching were extended so that
the fingerprint window actually covers those events, and fingerprints were
re-recorded for the architectural changes above.
## v1.5.0 (2026-07-13)
This release continues the architectural overhaul of Simu5G. Major themes
include consolidating Control Plane functions under the RRC module, adding QoS
support via DRBs and the SDAP protocol, restructuring Ip2Nic and other modules
for cleaner architecture, and improving type safety throughout the codebase.
Tested with INET-4.5.4 and OMNeT++ 6.3, compatible with INET-4.6.0 and OMNeT++
6.1 through 6.4.
### More explicit Control Plane modeling
Continuing the direction set in v1.4.3, code fragments that implement pieces of
the 3GPP Control Plane have been identified throughout the codebase and collected
under the `Rrc` module. `Rrc` is now a compound module with the following
submodules:
- **BearerManagement**: The former simple `Rrc` module, renamed and extended.
It now owns the lifecycle (creation, deletion, lookup) of all PDCP and RLC
entities. Previously, entity management was scattered across the monolithic
PDCP module and the `LteRlcUm`/`LteRlcAm` modules.
- **Registration**: Node registration and deregistration logic, previously
embedded in `Ip2Nic`, was moved here.
- **HandoverController**: Handover decision and execution logic was extracted
from `LtePhyUe` into this new module. This is architecturally more correct,
as handover is an RRC function, not PHY. The internal "handover packet"
misnomer was corrected to "beacon" (`HANDOVERPKT` -> `BEACONPKT`,
`broadcastMessageInterval` -> `beaconInterval`). Several parameters were
exposed as NED parameters (`hysteresisFactor`, `handoverDetachmentTime`,
`isNr`).
- **D2DModeController**: D2D mode selection was moved here from the former
`stack/d2dModeSelection/` directory, and D2D peer tracking from
`LteRlcUmD2D`.
### QoS support: SDAP, DRBs and per-bearer PDCP/RLC entities
QoS (Quality of Service) support was added through Data Radio Bearers (DRBs)
and the SDAP (Service Data Adaptation Protocol) layer, which is part of the 5G
NR protocol stack. The code is based on a contribution by Mohamed Seliem
(University College Cork); see releases v1.4.1-sdap and v1.4.1-sdap-2 for
details. In this release, the code was substantially reworked and integrated
into the main codebase.
In accordance with the 3GPP architecture, the PDCP and RLC layers were
transformed so that they purely consist of per-DRB entities, created and
configured by `BearerManagement` (RRC). Each DRB has dedicated PDCP TX/RX and
RLC TX/RX entity modules, wired directly to each other via per-bearer gate
connections.
Details:
- **SDAP protocol layer**: An SDAP implementation was added, providing
QFI-to-DRB routing with a JSON-configured `DrbTable`. The SDAP layer is
optional in NR NICs (enabled via `hasSdap=true`).
- **QFI propagation via GTP-U**: QFI is set by the application via DSCP,
picked up by `TrafficFlowFilter`/UPF, carried in the GTP-U protocol header
(mirroring the 3GPP PDU Session Container extension header), and extracted
by the gNB for SDAP routing.
- **QoS-aware proportional fairness scheduler**: A `QoSAwareScheduler` was
added to MAC, supporting QFI-based scheduling with configurable weight
constants. Enable with `LteMacEnb.schedulingDisciplineDl/Ul = "QOS_PF"`.
- **DRB configuration in JSON**: DRB configuration is split between SDAP
(`sdap.drbConfig` for QFI-to-DRB routing) and MAC (`mac.drbQosConfig` for
QoS scheduler parameters), both in JSON format.
- **Non-IP PDU session support**: SDAP was generalized for non-IP PDU session
types, with `PduSessionType` enum and `upperProtocol` in DRB configuration.
- **PDCP refactored into per-bearer entities**: The former monolithic PDCP
module (which had six subclass variants for LTE/NR × UE/eNB/D2D) was
replaced with per-bearer `PdcpTxEntity` and `PdcpRxEntity` modules, plus
`PdcpMux` for upper-layer routing and `DcMux` for Dual Connectivity X2
forwarding. Bypass entities handle the DC secondary leg. Entities communicate
via OMNeT++ gates, not C++ method calls.
- **RLC refactored into per-bearer entities**: The former `LteRlc` compound
module (containing `LteRlcUm`/`LteRlcUmD2D`, `LteRlcAm`, `LteRlcTm`) was
replaced with per-bearer TX/RX entity modules for all three RLC modes (UM,
AM, TM), plus `RlcMux` for MAC↔entity routing.
- **PDCP↔RLC directly wired**: PDCP and RLC entities are connected directly
via per-bearer gates. All submodules now reside directly at NIC level -- the
former `PdcpLayer` and `LteRlc` compound modules no longer exist.
- **Example simulations**: `simulations/nr/standalone_drb/` with
multi-UE, multi-QFI configurations.
### Ip2Nic decomposed, further module architecture improvements
The `Ip2Nic` module, which had accumulated various unrelated responsibilities
over time, was decomposed. Several code fragments were factored out into
separate modules:
- **`analyzePacket()` moved to Ip2Nic from PDCP**: Packet classification
(filling `FlowControlInfo` tags) was moved to where it logically belongs --
at the IP-to-NIC boundary. The `IpFlowInd` tag was eliminated. RLC type NED
parameters (`conversationalRlc`, etc.) also moved from PDCP to `Ip2Nic`.
- **HandoverPacketHolderUe/Enb**: Handover packet buffering was factored out
of `Ip2Nic` into separate modules. X2 tunneled packets are now received via
gates instead of C++ method calls.
- **TechnologyDecision**: Dual Connectivity technology selection logic was
extracted into a separate, configurable module that uses NED expressions.
Further module architecture improvements:
- **MAC turned into compound module**: MAC is now a compound module with `AMC`
and DL/UL `Scheduler` as proper `cSimpleModule` submodules (previously
created via `new` in C++). They perform their own staged initialization.
- **UPF and PgwStandard** now derive from INET's `ApplicationLayerNodeBase`.
- **PacketFlowObserver refactored to use OMNeT++ signals**: Direct C++ calls
from PDCP, RLC, and MAC into `PacketFlowObserver` were replaced with
OMNeT++ signals, fully decoupling the observer from protocol modules.
- Replaced method-call-based packet passing with gate connections in several
places: `LteHandoverManager`, `DualConnectivityManager`, `Ip2Nic` (X2 path).
### Type safety improvements
- **Strong typedefs**: `SIMU5G_STRONG_TYPEDEF` macro applied to `MacNodeId`,
`DrbId`, `LogicalCid`, and `Qfi`, preventing accidental mixing of ID types.
- **Direction enum**: `LteControlInfo.direction` changed from `unsigned short`
to a proper `Direction` enum.
- **C++ types extracted**: Types previously defined in `LteCommon.msg` were
moved into a dedicated `LteTypes.h` header.
- **ROHC header**: PDCP header compression now uses a proper ROHC header
representation instead of simply truncating the IP header.
- `FlowControlInfo`: `lcid` field renamed to `drbId`.
### Naming and layout cleanup
- Gate renames throughout the NIC for clarity and consistency:
`MAC_to_RLC`/`RLC_to_MAC` -> `upperLayerIn`/`upperLayerOut` and
`macIn`/`macOut`; `MAC_to_PHY`/`PHY_to_MAC` -> `phyOut`/`phyIn`;
`filterGate` -> `dnPppg`. Several `inout` gates split into separate `input`
+ `output` gates.
- Submodule renames: `pdcpUpperMux` -> `pdcpMux`, `rlcLowerMux` -> `rlcMux`,
`pppIf` -> `dpPpp` (in UPF/PGW).
- Module renames: `DualConnectivityManager` -> `DcX2Forwarder`,
`LteHandoverManager` -> `HandoverX2Forwarder`.
- Improved NED layout of NIC internals for better visualization in Qtenv:
data-path modules arranged vertically, control-plane modules on the left
edge, dynamically created PDCP/RLC entities positioned between muxes.
### Bug fixes
- `LteSchedulerEnb`: Fixed multi-UE starvation in multi-DRB scheduling.
### Other
- Added `tilx` fingerprints (resistant to module renames) to the fingerprint
test suite. Fingerprint test coverage for MEC simulations improved.
- `SplitBearersTable` turned into `std::ordered_map`.
## v1.4.5 (2026-07-09)
This release is a collection of bug fixes to the physical-layer error model
(CQI and BLER computation), the MAC layer, and the uplink scheduler. Several of
these fixes change simulation results for the affected configurations.
Tested with INET-4.5.4 and OMNeT++ 6.3, compatible with INET-4.6.0 and OMNeT++
6.1 through 6.4.
### PHY error model fixes
- **BLER table indexing**: `GetBLER_TU()`/`GetBLER_AWGN()` indexed the CQI/BLER
tables one row too low, making throughput results slightly optimistic.
- **CQI boundary condition**: An SNR exactly at the minimum (`minSnr`, -14 dB)
wrongly yielded the maximum CQI 15 instead of CQI 0, scheduling a noise-floor
UE at the highest MCS.
- **CQI 0 handling**: `LteRealisticChannelModel::error()` no longer treats CQI 0
(a valid "channel unusable" value, e.g. just after handover) as a fatal error;
the packet is simply dropped.
### MAC and scheduler fixes
- **HARQ process count**: The `harqProcesses` NED parameter (whose NR default is
5) was ignored by the C++ code, which used a hardcoded value of 8. The code now
honors the parameter, so NR uses 5 HARQ processes as v1.4.4 already intended.
Contributed by Esteban Egea Lopez (Universidad Politécnica de Cartagena).
- **RAC grant sizing**: A UE completing RACH on a poor uplink channel could get a
grant too small to even carry a Buffer Status Report, leaving it unable to
report its buffer and re-RACHing forever. Grants are now sized to at least 56 B.
### Other fixes
- **PacketFlowObserverEnb**: An unknown grant ID on an uplink MAC PDU (normal
during handover) now logs a warning instead of throwing a fatal error.
- **PacketFlowObserver**: BSR-only MAC PDUs (no RLC SDUs) are now tolerated
instead of triggering a fatal error.
- **AmcPilotAuto**: Using it with a D2D direction now fails with a clear error
message; scenarios with D2D should set `amcMode="D2D"`.
## v1.4.4 (2026-05-24)
This release contains bug fixes and improvements, including more realistic MAC
layer modeling and several MEC fixes.
Tested with INET-4.5.4 and OMNeT++ 6.3, compatible with INET-4.6.0 and OMNeT++
6.1 through 6.4.
### MAC improvements
- **RACH preamble collision modeling**: UEs now pick a random preamble index
when sending Random Access Channel (RAC) requests. The eNB detects collisions
when multiple UEs choose the same preamble in a TTI, causing all colliding
requests to fail. Failed UEs exercise the existing backoff/retry path. A new
NED parameter `numPreambles` (default 64) controls the preamble pool size.
While this is an abstraction of the real multi-step RACH procedure, it
faithfully captures preamble contention (the primary source of access
failures) with minimal additional model complexity.
- **NR MAC timer defaults adjusted**: `raResponseWindow` changed from 3 to 20,
`retxBsrTimer` from 40 to 320. The original values were the LTE defaults, too
aggressive for NR's finer timing granularity. Also adjusted `maxRacAttempts`
(10) and `racBackoffMax` (20) for both LTE and NR.
- **Default HARQ processes for NR changed to 5** (from 8), reflecting the
asynchronous nature of NR HARQ.
- **RAC/BSR timer parameters are now configurable from NED** (previously
hardcoded).
### Bug fixes
- **Ip2Nic**: Fixed issue #302 -- packets arriving at the old gNB just after a
handover are now forwarded to the new gNB over X2, instead of causing an error.
- **Ip2Nic**: Fixed fallback to NR node ID when a UE has no LTE ID, which is
necessary for handling NR-only UEs.
- **MAC**: Fixed ASSERT failure on D2D mode switching (`SinglePair-modeSwitching`
scenario). When switching from DM to IM mode, the MAC connection structure is
now preserved with empty buffers instead of being destroyed, so that switching
back to DM mode works correctly.
- **GtpUserX2**: Fixed `GtpUserMsg` chunk length to 8B, consistent with `GtpUser`.
- **MecOrchestrator**: Fixed `contextIdCounter` never being incremented, causing
every MEC app to overwrite the previous map entry at key 0.
- **MecOrchestrator**: Fixed missing return after a failure path that caused an
end-iterator dereference.
- **MecAppBase**: Fixed undisposed `HttpMessageStatus` objects on destruction.
- **MecResponseApp, MecRTVideoStreamingReceiver**: Fixed missing `localUePort`
parameter that was inadvertently removed during earlier refactoring.
- **RniService**: Fixed incomplete CamelCase renaming that caused the service to
not be found in the registry.
- **MEC**: Fixed uninitialized variables that caused non-deterministic fingerprint
failures in debug builds.
### Other changes
- **Binder**: `getNextHop()` renamed to `getServingNodeOrSelf()` for clarity.
- **UDP error handling**: Refactored several application modules (including
UeWarningAlertApp, UeRnisTestApp, UeRequestApp, and others) to use
`UdpSocket::ICallback`, fixing errors when receiving ICMP "destination
unreachable" indications. MEC apps now also properly close their UDP sockets.
- **Copyright headers adjusted**: Replaced generic "Authors" lines with precise
copyright lines and added SimuLTE copyright attribution to files derived from
SimuLTE.
- **INET 4.6 compatibility**: Added `checksumMode` parameter to emulation
examples alongside the existing `crcMode` for backward compatibility.
- **TrafficLightController**: Made backward compatible with OMNeT++ 6.1.
## v1.4.3 (2026-02-18)
This release represents a major milestone in the complete overhaul of the Simu5G
codebase to make it architecturally more compliant with the 3GPP
specifications, modernize the code, and adopt the best practices of the INET
Framework on which it is based. The goal is to pave the way for a clean
implementation of new protocol features such as TSN support.
Tested with INET-4.5.4 and OMNeT++ 6.3, updated for INET-4.6.0 compatibility.
Key achievements in this release:
- **More explicit Control Plane modeling**: Simu5G is advertised as a User Plane
simulator, but since it was also used to model dynamic scenarios such as
handovers, it always contained elements of the Control Plane distributed across
various modules. The new direction is to make these elements more explicit and
centralized, such as creating dedicated RRC (Radio Resource Control) and
Session Management Function (SMF) implementations. It is an explicit non-goal
to simulate Control Plane messaging -- its functionality will be implemented
with C++ method calls across modules. Thus, Simu5G remains a User Plane
simulator, but with the possibility to more faithfully model dynamic
scenarios with heavy Control Plane involvement. While this goal is not fully
realized in this release, many changes point into that direction.
- **Control info refactoring**: Cleaned up `UserControlInfo` and
`FlowControlInfo` by removing 5+ unused fields and splitting out smaller,
focused tags. For example, IPv4 addresses, only used between `Ip2Nic` and PDCP,
have been factored out into an `IpFlowInd` tag. This improves modularity,
reduces coupling between protocol layers, and makes the code easier to
maintain and extend.
- **Added vital missing fields to PDCP and MAC headers**: Protocol layers now
use proper header fields instead of "tunnelling" information via
`UserControlInfo` and `FlowControlInfo` packet tags that would not exist in a
real implementation. For example, PDCP sequence numbers are now carried in
PDCP headers, and LCIDs are stored in MAC PDU subheaders. This makes the
simulation more realistic and packet contents more inspectable in Qtenv.
- **Explicit setup of logical connections instead of on-the-fly discovery**:
This is a key architectural change, which also largely motivated the
previous items. In previous iterations of Simu5G, data structures associated
with logical connections / bearers were created in each protocol layer as they
encountered packets that belonged to new connections. Moreover, part of the
connection state was carried along by the packets in `FlowControlInfo` tags
instead of stored inside the protocol. While this modeling approach still
allowed for faithful simulation of the traffic while keeping the
implementation simple, it has become a roadblock for implementing complex
dynamic scenarios where connections come and go. In this iteration,
centralized session and bearer management (SMF-like functionality) was added
to the `Binder` module, and RRC modules were added to NICs to carry out local
configuration. This brings the architecture closer to the 3GPP control/user
plane separation, making it easier to implement features like handovers
correctly. This is work in progress: SMF is still part of `Binder` and not a
separate module, and connection setup is still triggered by the first packet
of the connection hitting PDCP on the way out. However, moving the SMF code
into its own module will be trivial, and the single `Binder` method call in
PDCP can now be easily replaced with static configuration or with calls from a
more detailed Control Plane implementation.
- **Removed incomplete MIMO support**: Removed MIMO-related code and parameters.
The existing MIMO code was incomplete (e.g., PMI values were computed but
never used). Removing it simplifies the codebase and model parameterization,
and avoids confusion about capabilities. MIMO support will be added in a future
release, with a different approach.
- **Initialization cleanup**: Reorganized module initialization into well-defined,
Simu5G-specific init stages. This eliminates hidden cross-module dependencies,
makes the initialization order explicit and verifiable, and prevents subtle bugs
caused by modules accessing uninitialized data in other modules.
Further notable changes:
- In UE models, `masterId` and `nrMasterId` were renamed to `servingNodeId` and
`nrServingNodeId`. The old names were confusing because "Master" has a
specific meaning in Dual Connectivity (Master eNB vs Secondary gNB), unrelated
to the UE's serving node.
- In UE models, the `macCellId`, `nrMacCellId` parameters were removed. In
practice, the code already used the serving node ID as cell ID.
- `macNodeId` assignment was moved to NED, and now it is based on the new
`simu5g_seq()` NED function that generates an integer sequence. This replaces
the earlier approach where node IDs were assigned by `Ip2Nic` during
initialization, and stored back into the module parameters for other modules to
use.
- `LteRlcPduNewData` and `LteRlcSdu` packet chunks were converted to packet
tags, as they represent internal metadata rather than actual protocol data.
- In the C++ code, merged the `ENODEB` and `GNODEB` node type enum values into a
single `NODEB` value, with a separate `isNr` flag where needed. This change
simplified a large number of "if" conditions throughout the codebase.
To port your existing Simu5G simulations to this version, apply the following
changes to the ini files:
- Change `masterId` to `servingNodeId` (and `nrMasterId` to `nrServingNodeId`),
unless it refers to the Master/Secondary distinction in a Dual Connectivity
setup.
- Remove `macCellId` and `nrMacCellId` parameter assignments for UE modules.
- Delete ini entries that set the following removed MIMO-related parameters:
`numRus`, `ruRange`, `ruStartingAngle`, `ruTxPower`, `antennaCws`,
`muMimo`, `pmiWeight`, `lambdaMinTh`, `lambdaMaxTh`, `lambdaRatioTh`,
`feedbackGeneratorType`.
- For `initialTxMode`, the following values are no longer valid:
`SINGLE_ANTENNA_PORT5`, `OL_SPATIAL_MULTIPLEXING`, `CL_SPATIAL_MULTIPLEXING`,
`MULTI_USER`. Remove the parameter assigment to use the default.
There are many more changes that potentially affect existing simulations, and
projects extending, or built on top of, Simu5G. They cannot all be covered here
in detail - see the git history for details.
## v1.4.2 (2025-11-27)
This is primarily a bugfix release.
- Pdcp: Fixed Dual Connectivity bug where separate PDCP entities were
incorrectly created for LTE and NR legs of a Split Bearer instead of using a
single shared entity. This fix breaks RLC-UM packet loss statistics which
(incorrectly) inferred packet loss from PDCP sequence numbers.
- RlcUm: Removed packet loss statistics that incorrectly relied on PDCP sequence
numbers (PDCP sequences are not contiguous in Dual Connectivity setups)
- PacketFlowManager: Renamed to PacketFlowObserver, updated NED documentation.
- Statistics collection refined, e.g. remove recording "sum" and/or "mean" where
it does not make sense; use new "rateavg" filter for computing average
throughput.
- Binder: New utility functions: isGNodeB(), getUeNodeId().
- Apps: Added sequence numbers to VoIP and VoD packet names, to facilitate
tracing with Qtenv.
- NED documentation: Added content to simu5g-index.ned including version number
and WHATSNEW.
## v1.4.1-sdap-2 (2026-03-03)
This release improves on the simu5g-1.4.1-sdap release that added SDAP (Service
Data Adaptation Protocol) layer support to Simu5G. Contributed by Andras Varga
(OMNeT++ Core Team).
The most important changes:
- New simulations that exercise the code more: Multi-UE, multi-app, multi-QFI
configurations were added into `omnetpp_drb.ini` under `nr/standalone`. Based
on the Simu5G#294 bug report by Jonathan "Toaaster" Ebert.
- Fixed QFI propagation: QFI was originally added to packets by the application
(`VoipSender`) as a packet tag (`QfiTag`). However, this tag did not make it to
UPF, because it was already stripped by the local PPP interface on
transmission. This mechanism was replaced by the VoipSender app setting DSCP
on the packet, which UPF now interprets as QFI (simplified PDR matching). From
then on, QFI is now carried through the GTP-U tunnel in the GTP header
(mirroring the real 5G PDU Session Container extension header), instead of
relying on QoS tags that were being stripped by PPP. The gNB extracts QFI from
the GTP-U header to restore QoS tags for SDAP routing.
- DRB configuration changes: The DRB configuration is now split between SDAP and
MAC layers, each only knowing as much as they need for their operation.
QFI-to-DRB routing configuration went into `sdap.drbConfig`, while QoS
parameters for the scheduler (GBR, delay budget, PER, priority) went into
`mac.drbQosConfig`. Moreover, DRB configuration is now specified in JSON,
replacing the previous text file-based configuration.
- Fixed multi-UE DL starvation (fixes Simu5G#294): `MacDrbMultiplexer`
incorrectly used LCID as the `nrRlc[]` array index, assuming LCID equals the
DRB index. When multiple UEs shared the same DRB, only the first UE received
data. Fixed by learning the LCID-to-gate mapping from RLC-to-MAC traffic.
- MEC fixes: There were several bug fixes in the MEC code, such as
`MecOrchestrator` (contextId counter was never incremented), `MecOrchestrator`
(missing return after failure path causing end-iterator dereference),
`MecAppBase` (eliminate undisposed objects), fix uninitialized variables in
various modules (fixing long-standing fingerprint failures of certain MEC
simulations in debug mode).
## v1.4.1-sdap (2025-10-06)
Compatible with OMNeT++ 6.2.0 and INET 4.5.4.
This specialized branch release introduces SDAP protocol support, multiple DRBs
and advanced QoS capabilities to Simu5G for enhanced 5G network simulations.
Please note that future main releases may not include these features or may
incorporate them in a different form, as the primary development focus remains
on architectural refactoring and foundational improvements. The changes were
contributed by Mohamed Seliem (University College Cork), with improvements by
Andras Varga (OMNeT++ Core Team).
Reference paper: "QoS-Aware Proportional Fairness Scheduling for Multi-Flow 5G
UEs: A Smart Factory Perspective". Mohamed Seliem, Utz Roedig, Cormac Sreenan,
Dirk Pesch. IEEE MSWiM, 2025.
New Features:
- Added an SDAP protocol implementation with reflexive QoS capabilities (NrSdap
and ReflectiveQosTable modules). Available using the NRUeSdap (UE) and
gNodeBSdap (gNodeB) node types that contain the NRNicUeSdap and NRNicEnbSdap
NIC types, respectively.
- DRB (Data Radio Bearer) support with multi-QFI/QoS handling for realistic 5G
bearer management simulations. This feature is available using NRUeDrb (UE)
and gNodeBDrb (gNodeB) node types that contain the NRNicUeDrb and NRNicEnbDrb
NIC types, respectively. It can be configured using the numDrbs parameter.
QFI-to-DRB mappings can be defined in a context file (see SDAP's
qfiContextFile parameter) with 5QI parameters and QoS requirements.
- QoSAwareScheduler with QFI-based Proportional Fair scheduling using QfiContextManager.
Enable QoS scheduling with LteMacEnb.schedulingDisciplineDl/Ul="QOS_PF".
- Better representation of compressed headers in PDCP. (Note that header compression is
disabled by default; enable using PDCP's headerCompressedSize parameter.)
- New example simulations: simulations/nr/standalone/omnetpp_sdap.ini and omnetpp_drb.ini,
each with Standalone, VoIP-DL, and VoIP-UL configurations demonstrating SDAP functionality
and multi-DRB support with QoS-aware scheduling.
## v1.4.1 (2025-10-06)
This is a minor update that brings further refactoring of the C++ code for clarity,
improvements in the C++ interface of the Binder module, and some minor bug fixes.
These improvements were contributed by Andras Varga (OMNeT++ Core Team).
Notable changes:
- Binder: Partial rationalization of the C++ interface, via
renaming/replacing/removing methods. See the git history for changes.
- Updated IP addresses in the IPv4 configuration files: use 10.x.x.x
addresses for the Core Network, and 192.168.x.x addresses for external
addresses
- Visual improvement: node IDs are now displayed over module icons
- In MEC, do not use module IDs for bgAppId, deviceAppId and other IDs, and do
not encode module ID into module names. That practice made simulations brittle
for regression testing via fingerprints.
- PDCP: Eliminated tweaking of srcId/destId in FlowControlInfo when sending
downlink packets over the X2 link in a Dual-Connectivity setup.
- Various additional fixes and changes to improve code quality.
## v1.4.0 (2025-09-18)
Compatible with **OMNeT++ 6.2.0** and **INET 4.5.4**.
This release marks an important milestone in the ongoing transformation of
Simu5G. While not introducing behavioral changes, this intermediate release
focuses on restructuring the codebase to improve clarity, safety, and
maintainability. Major updates include a reorganized directory structure,
enforcing a consistent naming convention, making make packets more easily
inspectable, and refactoring of parts of the C++ code to pave the way for
changes in future versions. Although the release is not source-compatible with
previous versions, existing simulations will continue to work unchanged once
adjusted to follow the various rename operations. These improvements were
contributed by Andras Varga (OMNeT++ Core Team).
Renames:
- Sources are now under src/simu5g/ instead of just src/, so that C++ includes
start with "simu5g/". This helps identifying Simu5G includes when Simu5G is
used as a dependency of other projects.
- Some folders were moved inside the source tree to a more logical location. For
example, the simu5g/nodes/mec/ subtree was promoted to simu5g/mec/.
- Several source folders were renamed to more closely follow the all-lowercase
convention. For example, mec/UALCMP/ became mec/ualcmp/, and mec/MECPlatform
became just mec/platform.
- Several classes were renamed to ensure that only the first letters of acronyms
are uppercase. For example, MECHost became MecHost.
- Several parameters were renamed to enforce camelcase names. For example,
bs_noise_figure became bsNoiseFigure, and fading_paths became numFadingPaths.
If you have existing Simu5G simulations, review the ini files carefully and
update the parameter assignments accordingly. (Caveat: Assignment lines that
refer to the old names will be simply ignored by the simulation -- there is no
error message for that!)
- The PdcpRrc modules were renamed to just Pdcp. Likewise, pdcpRrc submodules
in NIC compound modules became pdcp.
Further refactoring:
- Several protocol header classes, while defined in msg files, contained heavy
customization in C++ code, including the addition of new fields. Since the
writing of those classes, the message compiler in OMNeT++ gained enough
features so that most of the customizations were no longer needed, and the
desired effect could be achieved in msg files only. This refactoring has the
benefit of making packets more inspectable from Qtenv, and packet contents can
now be serialized using parsimPack (useful for more thorough fingerprint
tests).
- MacCid is a central data type that pairs an LCID with a nodeId to uniquely
identify a logical channel. It used to be a packed integer, and now it was
turned into a C++ class with separate fields for the node ID and LCID and with
accessor methods, for increased type safety.
- carrierFrequency used to be a variable of the type double throughout the
codebase. The type was changed to GHz (using INET's units.h) for increased
type safety. This also helped identifying a bug in certain channel models
(LteRealisticChannelModel, BackgroundCellChannelModel) where a double
representing GHz instead of Hz was used in computing path loss, resulting
in underestimated path loss values. [Correction from a later release: the
"bug" was not one, and the change was reverted. The affected terms,
20log10(40 pi d fc/3) in the RMa/SMa LOS path loss, take fc in GHz: they
are the free-space term 20log10(4 pi d f/c) with the unit conversion
folded into the constants, so evaluating them in Hz overstated the LOS
path loss by 180 dB. The formulas were unreachable from the example
simulations at the time, so no published result was affected.]
- Binder received several WATCHes for increased transparency in Qtenv, and
an overhaul of a subset of its API and internal data structures.
- In the Pdcp modules, the unused EUTRAN_RRC_Sap port (and associated handling
code) was removed.
- Refactoring of internals in several protocol modules, including MAC, PDCP and
RLC implementations.
Build:
- Made the command line build consistent with the IDE build. src/Makefile is now
generated/updated implicitly on every build, no need to type "make makefiles".
## v1.3.1 (2025-09-18)
This is a minor update for Simu5G-1.3.0. In addition to fixing regressions
in the previous release and making some cosmetic improvements, the main highlight
of this release is the revamp of the fingerprint test suite, which now provides
a more comprehensive safety net against future regressions. Changes in this
release were contributed by Andras Varga (OMNeT++ Core Team).
Changes:
- Example simulations: Marked abstract configs as such (abstract=true) in omnetpp.ini files
- FlowControlInfo's MacNodeId fields are now properly shown in Qtenv object inspectors
- Replaced EV_ERROR << lines with throwing cRuntimeError
- TrafficLightController: fixed startState NED parameter (also changed type from int to string)
- Fingerprints: CSV files merged into simulations.csv, added missing simulations,
standardized on the set of fingerprints computed (tplx, tNl, sz), translated
gen_runallexamples.py into Python and improved it
Fix regressions in v1.3.0:
- MECResponseApp: fixed wrong @class annotation
- BackgroundScheduler: fix "binder_ not initialized" error
- MecRequestForegroundApp, MecRequestBackgroundGeneratorApp: add back lost parameter defaults
- BackgroundCellTrafficManager: fix "Not implemented" thrown from getBackloggedUeBytesPerBlock()
- tutorials/nr/omnetpp.ini: fix missing unit for txPower parameter (dBm)
## v1.3.0 (2025-02-06)
- Compatible with **OMNeT++ 6.1.0** and **INET 4.5.4**
- New modules: MultiUEMECApp, MecRnisTestApp, UeRnisTestApp
- Added NED documentation for modules
- Increased reusability of modules via changes such as replacing hardcoded module
paths in the C++ code with NED parameters (binderModule, macModule, etc.), and
elimination of ancestorPar() calls by introducing local parameters instead. *
- Other NED adjustments, such as removal of unused NED parameters and splitting
NED files to have one module per file. See doc/NED-changes.txt for details. *
- Extensive C++ modernization, and adaption of more OMNeT++ best practices. *
- Various bug fixes.
- Changes marked with an asterisk were contributed by Andras Varga (OMNeT++ Core
Team).
## v1.2.3 (2025-01-10)
- Added support for **OMNeT++ 6.1.0** and **INET 4.5.4**.
## v1.2.2 (2023-04-19)
- Compatible with **OMNeT++ 6.0.1** and **INET 4.5**.
- Tested on Ubuntu 22.04 and macOS Ventura.
## v1.2.1 (2022-07-19)
- Compatible with **OMNeT++ 6.0** and **INET 4.4.0**.
- Tested on Ubuntu 20.04.
- Modifications to support the latest versions of OMNeT++ 6.0 and INET v4.4.0.
- Refactoring of simulation and emulation folders.
- Various bug fixes.
## v1.2.0 (2021-08-30)
- Compatible with **OMNeT++ 6.0 (pre10 and pre11)** and **INET 4.3.2**.
- Tested on Ubuntu 16.04, 18.04, 20.04, macOS Catalina, and Windows 7.
- Added modelling of **ETSI MEC** entities.
- Support for **real-time emulation capabilities** (Linux OS only).
- Modelling of background cells and background UEs for **larger scale** simulations and emulations.
- Several bug fixes.
## v1.1.0 (2021-04-16)
- Compatible with **OMNeT++ 5.6.2** and **INET 4.2.2**.
- Tested on Ubuntu 16.04, 18.04, 20.04, macOS Catalina, and Windows 7.