BearerConfigurator.ned

NED File src/simu5g/corenetwork/bearerConfigurator/BearerConfigurator.ned

Name Type Description
BearerConfigurator simple module

Central configurator of the network's data radio bearers.

Source code

//
//                  Simu5G
//
// Authors: Andras Varga (OpenSim Ltd)
//
// This file is part of a software released under the license included in file
// "license.pdf". Please read LICENSE and README files before using it.
// The above files and the present reference are part of the software itself,
// and cannot be removed from it.
//

package simu5g.corenetwork.bearerConfigurator;

//
// Central configurator of the network's data radio bearers.
//
// This module does not model a single 3GPP network function. 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 PDU sessions and QoS flows, while the
// NG-RAN decides how QoS flows map onto DRBs and derives the radio configuration
// (TS 23.501 5.7.1, TS 38.300 12); in EPS, the corresponding roles are spread across
// the MME and the eNB. Here every bearer is authored in one place instead, and the
// signalling that would carry the configuration (N1/N2/S1/RRC procedures) is not
// modeled: within the model, the RAN never authors a bearer of its own -- every
// bearer comes from this module's tables.
//
// One cellular network holds one instance of this module, alongside its ~Binder. Like
// the Binder, it is always reached through module paths supplied in parameters
// (bearerConfiguratorModule), never through hardcoded ones, so several cellular
// networks -- each with its own Binder and BearerConfigurator pair -- can coexist
// within one simulation. The "ue" patterns of the definition tables range over the
// UEs registered in this instance's Binder only, but are matched against module paths
// relative to the toplevel network, so in such a setup the entries (and the
// module-path parameters) name their nodes by qualified paths, e.g. "networkA.ue[*]".
//
// Modeling abstractions and current limitations:
//  - Bearer establishment is a direct call into the RRC of each node involved; no
//    signalling procedure carries it.
//  - Packet-triggered establishment (onDemandDrbs) is a simulation policy. In 5GS, a
//    first UL packet with an unmapped QFI would ride the already-established default
//    DRB, and the gNB could reconfigure the mapping afterwards (TS 38.300 Annex A);
//    creating the DRB before the first packet is delivered is a shortcut.
//  - One PDU session (in EPS terms: one PDN connection) per UE is assumed. QFI
//    mappings, the default DRB and the pduSessionType are therefore scoped per UE,
//    although the spec scopes all of them per PDU session (TS 37.324); a UE with
//    several sessions, e.g. toward multiple DNs or with two session types, cannot
//    be described yet.
//  - The QoS characteristics attached to a definition describe the DRB as a whole.
//    In 5GS they belong to QoS flows, and flows with different QoS profiles may
//    legitimately share a DRB; per-flow QoS is not modeled.
//  - legSelection is a Simu5G extension: 3GPP steers split bearers by PDCP-level
//    controls (primaryPath, ul-DataSplitThreshold), not by per-PDU expressions.
//
// The staticDrbs parameter is the network's data radio bearer configuration: one entry per
// bearer per UE, describing the bearer before and independent of its establishment (modeled
// on the DRB-ToAddMod and RLC-BearerConfig records of TS 38.331). This module tells the RRC
// of each node involved in a bearer -- the UE and its serving node -- what to set up, and
// RRC pushes on what each of its layers consumes. Nothing reads this configuration back out.
//
// A static bearer is not only configured but also established up front, in the last
// initialization stage: each entry results in the same establishment call that
// packet-triggered setup makes, so traffic finds the bearer in place. A dual-stack UE's
// bearer is established on the stack that packet-triggered establishment would pick
// (split into per-technology legs when the UE is served by a node pair in dual
// connectivity); an entry whose UE is attached to no cell at that point is a
// configuration error. To make the static configuration the only source of bearers,
// disable packet-triggered establishment via the establishBearersOnDemand parameter of
// ~NrSdap (or ~Ip2Nic, for stacks without SDAP); see the VoIP-DL-MultiQfi-NoOnDemand
// configuration of the simulations/nr/standalone_drb example.
//
// Because an entry names its UE by module path rather than by node id, the configuration
// follows the UE from cell to cell, and neither end of the radio link is configured
// directly from the ini.
//
// staticDrbs fields:
//  - coreNetwork (string, required): "5gc" or "epc" -- which bearer architecture selects the
//    bearer. A "5gc" bearer is selected by the QFIs mapped onto it (mappedQfis; needs SDAP in
//    the stack); an "epc" bearer is selected by packet filters (filters; for stacks without
//    SDAP). Stated per entry, never inferred; each receiving RRC checks it against its stack.
//  - ue (string): module path of the UE node, relative to the network; patterns are allowed,
//    so one entry can describe a bearer of many UEs (e.g. "ue[*]")
//  - drbId (int): DRB identity, 1..32 (TS 38.331 DRB-Identity)
//  - profile (string, optional): name of a drbProfiles entry supplying defaults for the
//    fields it does not spell out itself
//  - mappedQfis (int[], optional, "5gc" only): QFI values (0..63) mapped to this DRB; an entry without
//    it does not take part in SDAP's QFI-to-DRB mapping. This field maps already-assigned
//    QFIs onto the DRB; which QFI a packet carries is decided by the QFI classification
//    rules (the dlQfiRules and ulQfiRules parameters below)
//  - filters (string[], optional, "epc" only): packet filters selecting this bearer, each
//    an inet::PacketFilter -- a message-name pattern (e.g. "VoIP*") or an expression written
//    as "expr(...)" (e.g. "expr(udp.destPort == 3000)"). An expression sees the packet that
//    triggers establishment, i.e. an UL-triggered and a DL-triggered flow present swapped
//    port/address roles; a list can carry both spellings.
//  - lcg (int, optional): the bearer's logical channel group (0..3;
//    mac-LogicalChannelConfig). In 3GPP an LCG only groups logical-channel buffers
//    for buffer status reporting; that Simu5G's MAC scheduler additionally serves
//    lower LCG indices first is a Simu5G scheduling policy, not spec semantics (the
//    spec's per-logical-channel priority is a separate parameter, not modeled, and
//    NR allows 8 LCGs where this model keeps LTE's 4). Omitted = derived from the
//    QoS profile's priority level (bucketed by lcgPriorityBounds), or 0 when the
//    definition carries no "qosPriorityLevel"
//  - rlcMode (string, optional when the definition carries a "packetErrorRate"): RLC
//    mode ("AM" or "UM"; "TM" is rejected -- 3GPP transparent mode carries
//    BCCH/PCCH/SRB0-class channels, not DRBs); omitted = derived from the QoS
//    profile's packet error rate
//    (packetErrorRate <= amPerThreshold -> "AM", else "UM": a PER target HARQ alone
//    cannot meet gets ARQ).
//    Required, in the entry or its profile, when there is nothing to derive it from.
//  - primaryPath (string, default "MCG"): on a split bearer (two legs), the preferred leg --
//    used in either direction whenever the bearer is not splitting; must be one of its two
//    legs (TS 38.331 PDCP-Config, TS 38.323 5.2.1; applied by ~DcPdcpLegSplitter).
//  - ulDataSplitThreshold (int bytes, or "infinity"; default "infinity"): uplink only. How
//    much of a split bearer's data must be queued waiting to send (in its legs' RLC buffers)
//    before the UE uses the second leg as well as primaryPath. "infinity" means never -- the
//    uplink stays on primaryPath. (Only the UE has both legs' queues locally; downlink has no
//    such threshold, see dlLegSelection.)
//  - ulLegSelection (string, optional): once the uplink is using both legs (at or above the
//    threshold), which leg each PDU takes -- an expr(...) over packetOrdinal (a running count
//    of the bearer's PDUs) returning the leg number, 0 or 1 (e.g. "expr(packetOrdinal % 2)"
//    for round-robin). Default when omitted: the less-loaded leg. Set ulDataSplitThreshold to
//    0 to have it decide every uplink PDU; stating it while leaving the threshold at infinity
//    is rejected.
//  - dlLegSelection (string, optional): the downlink counterpart, applied at the DC master.
//    The master cannot weigh the secondary leg's queue (it is at another node, across X2), so
//    downlink has no threshold or load-balancing: with dlLegSelection each downlink PDU takes
//    the leg it returns, and without it the downlink stays on primaryPath. (Real downlink
//    split flow control is X2-feedback-driven and is not modeled.)
//  - legs (string[]/object[], optional): the cell groups that serve this bearer, i.e. its
//    RLC bearers (TS 38.331 RLC-BearerConfig). One leg = an MCG or an SCG bearer, both =
//    a split bearer (TS 37.340; stated in that order). An element is either a cell group
//    name ("MCG" or "SCG"), or an object naming it and overriding the RLC configuration
//    it inherits from the entry: {leg: "SCG", rlcMode: "AM", soFraming: true,
//    snFieldLength: 18}. Omitted = the configuration does not state the legs and RRC
//    derives them, as it always has. An SCG bearer's PDCP still terminates at the master
//    node -- the core network delivers the UE's traffic there -- and every PDU is
//    relayed to the secondary over X2 (an MN-terminated SCG bearer in TS 37.340 terms).
//  - pduSessionType (string, optional): "IPv4", "IPv6", "IPv4v6", "Ethernet", "Unstructured";
//    default: "IPv4"
//  - upperProtocol (string, optional): INET protocol name for upper layer dispatch (this is
//    normally only needed for "Unstructured" PDU sessions); default: derived from
//    pduSessionType
//  - isDefault (bool, optional): marks this as the default DRB for the UE -- the fallback
//    when no QFI-to-DRB mapping ("5gc") or packet filter ("epc") matches. If no entry of
//    a UE is marked in either table, the UE's single static bearer takes the role; a UE
//    with several bearers must mark one explicitly.
//  - suppressSdapHeader (bool, optional, "5gc" only): the bearer's packets carry no SDAP
//    header (TS 38.331 sdap-HeaderDL/UL "absent"). Only meaningful on the default bearer
//    (any other bearer with at most one mapped QFI is headerless already), and only sound
//    when a single QoS flow actually rides it: the receiver assigns every headerless
//    packet the bearer's sole mapped QFI (QFI 0 when none is mapped), and the sender
//    verifies each packet against that value, stopping with an error when a second flow
//    shows up. The header decision itself is computed by this module and delivered per
//    bearer; SDAP applies it as pushed.
//  - gbr (bool), packetDelayBudget (double, ms), packetErrorRate (double),
//    qosPriorityLevel (int) -- all optional: the
//    QoS profile of the bearer's flows (5QI characteristics). Any of them present marks the
//    bearer as having a QoS profile, which RRC pushes into the eNB/gNB MAC for QoS-aware
//    scheduling.
//
// Field groups that repeat across entries can be named once in the drbProfiles parameter (a
// JSON map of name -> field group) and referenced from entries via their "profile" field. A
// profile describes what the bearer is, so it may hold any entry field except the ones that
// say which UE it belongs to (ue, drbId), which architecture and flows select it (coreNetwork,
// mappedQfis, filters, isDefault).
//
// A commonly used subset of the standardized QoS characteristics rows -- the core 1..9
// of each table; both tables define many more -- is available as predefined profiles,
// referenced by name without being defined: "qci-1".."qci-9" (TS 23.203 Table 6.1.7-A)
// and "5qi-1".."5qi-9" (TS 23.501 Table 5.7.4-1). A row carries what the spec
// standardizes -- gbr, qosPriorityLevel, packetDelayBudget, packetErrorRate -- and
// nothing else: the RLC mode and the logical channel group are RAN choices, derived
// from those characteristics by default (the way a gNB derives its AS configuration
// from the delivered QoS profile; see the rlcMode and lcg field descriptions) and
// stated on the entry only to override, e.g.
// {coreNetwork: "5gc", ue: "ue[*]", drbId: 1, mappedQfis: [1, 2], profile: "5qi-1"}.
// A drbProfiles entry may not redefine a predefined name. NOTE the spec's priority
// scales (QCI 1..9, 5QI 10..90) differ from each other and from the small hand-picked
// values older configurations use. The QoS-aware scheduler weights bearers by
// 1/qosPriorityLevel, so only priority RATIOS matter to it and the two spec catalogs
// discriminate identically; but the absolute values still drive the lcgPriorityBounds
// bucketing (whose defaults suit the 5QI scale: single-digit priorities all land in
// LCG 0), so profiles from different scales still should not be mixed within one
// network.
//
// Example (in an ini file):
//
// <pre>
// *.bearerConfigurator.drbProfiles = {
//     voice:  {rlcMode: "UM", gbr: true, packetDelayBudget: 100, packetErrorRate: 1e-2,
//              qosPriorityLevel: 2}
//     }
// *.bearerConfigurator.staticDrbs = [
//     {coreNetwork: "5gc", ue: "ue[*]", drbId: 1, mappedQfis: [1, 2], profile: "voice"}
//     ]
// </pre>
//
// The onDemandDrbs parameter describes bearers that are created when traffic first
// matches them, instead of being configured up front. Entries have the same fields as
// staticDrbs minus drbId: an on-demand bearer's id is assigned at creation, so
// definitions can never collide over ids ("ue" may also be omitted, meaning every UE).
// A "5gc" entry serves the QFIs in its mappedQfis: the first packet of an uncovered QFI
// creates the DRB (SDAP asks this module on a QFI-to-DRB lookup miss), and later QFIs
// of the same entry join it. An "epc" entry is matched by its filters against the
// packet that triggers bearer establishment, and an entry with isDefault=true catches
// the flows no filter matched ("5gc" entries cannot be the default: the default DRB is
// where unmapped QFIs go, so it must exist up front). A created bearer's definition is
// delivered to the RRCs involved exactly like a staticDrbs entry. Matching order is
// staticDrbs entries first, then onDemandDrbs entries, each in table order, first
// match wins.
//
// A flow that no definition covers is a configuration error: every on-demand bearer's
// properties come from a definition entry, never from the packet. The parameter's
// default value keeps configurations that author nothing working, whichever stack they
// run: for SDAP-less stacks it carries the well-known packet-name classes as ordinary
// catch-all definitions ("VoIP*" = LCG 0, "gaming*" = LCG 2, "VoD*" = LCG 1, everything
// else LCG 3, all RLC UM), and for SDAP stacks a single default bearer (the last row,
// "5gc"), header-suppressed: an unauthored run carries the one default QoS flow with no
// SDAP header on the wire, and a run whose traffic actually shows up with several QFIs
// stops with an error asking for authored bearers (or an unsuppressed default) instead
// of silently mixing its flows. Overriding the parameter replaces the whole set
// with the configuration's own.
// An "epc" entry describes bearers of SDAP-less stacks only and a "5gc" entry those of
// SDAP stacks only; a "ue" pattern (or an omitted "ue") covering UEs of both kinds
// simply skips the incompatible ones, but an entry whose explicit "ue" pattern matches
// no UE with a compatible stack is an error. So in any given network only the rows for
// the stacks present take effect, and the two default rows of the two kinds coexist
// harmlessly: the "5gc" default bearer is what lets a UE with SDAP run unauthored (its
// QFI-to-DRB table would otherwise be empty and the first packet would find no bearer),
// the "epc" rows do the same for a UE without.
// D2D and multicast bearers are outside the definition system: the tables describe
// infrastructure (Uu) bearers, while those are sidelink ones. They are established
// with a fixed configuration (RLC UM, LCG 3). The model has no sidelink bearer
// vocabulary and needs none: the only multicast in the model is D2D groupcast, which
// is kept working as it stands, and the network never originates multicast of its own.
//
// Example (in an ini file; the first entry suits a stack with SDAP, the other two
// one without):
//
// <pre>
// *.bearerConfigurator.onDemandDrbs = [
//     {coreNetwork: "5gc", ue: "ue[*]", mappedQfis: [3, 4], profile: "5qi-3"},
//     {coreNetwork: "epc", filters: ["expr(udp.destPort == 3000)"], lcg: 0, rlcMode: "UM"},
//     {coreNetwork: "epc", isDefault: true, lcg: 3, rlcMode: "UM"}
//     ]
// </pre>
//
// See the VoIP-DL-MultiQfi-OnDemandDrb configuration of simulations/nr/standalone_drb
// ("5gc") and the SingleCell-DL-OnDemandDrb configuration of simulations/lte/tutorial
// ("epc") for working setups.
//
// The dlQfiRules and ulQfiRules parameters author the network's QFI classification:
// which QoS flow (QFI) each packet belongs to. The bearer definitions above map
// already-assigned QFIs onto DRBs (mappedQfis); these two tables are where the QFIs
// themselves are assigned, once per direction at its ingress. The rules are
// delivered from here to their evaluation sites -- dlQfiRules to the
// ~TrafficFlowFilter at each core-network tunnel entry (modeling the PDR/QER rules
// the SMF installs into a UPF over N4 at session setup), ulQfiRules to each UE's
// ~QosFlowClassifier (modeling the QoS rules NAS signaling installs into a UE at
// PDU session establishment, TS 23.501 5.7.1.4) -- and the sites never author rules
// of their own: the ini author writes the operator's classification policy here,
// and this module plays the signaling the model does not have.
//
// Rule fields (both tables; evaluated in order at each site, first match wins):
//  - filter (string, optional): an inet::PacketFilter -- a message-name pattern
//    (e.g. "*VoIP*") or an expression written as "expr(...)"
//    (e.g. "expr(udp.destPort == 3000)"); omitted = the rule matches every packet
//  - qfi (int, 0..63) or dscpAsQfi (bool): the QFI to assign -- a fixed value, or
//    the packet's IPv4 DSCP field read as the QFI (exactly one of the two)
//  - node (string, dlQfiRules only, optional): module-path pattern of the
//    core-network nodes whose tunnel-entry filter gets the rule (relative to the
//    network, e.g. "upf" or "**.upf_mec"); omitted = every such node
//  - ue (string, ulQfiRules only, optional): module-path pattern of the UEs that
//    get the rule, matched like the bearer tables' "ue" field; omitted = every UE
//    with SDAP
//
// The two directions are authored separately, and a conversation that needs
// classification in both states a rule in each table, each written from its own
// direction's perspective. There is no sharing or reversal between them: the same
// filter means different things at the two ends (in "expr(udp.destPort == 3000)"
// the destination port is the UE's application port for downlink traffic and the
// server's for uplink), and a filter expression cannot be reversed mechanically.
// This mirrors the spec's own shape -- downlink PDRs at the UPF, uplink QoS rules
// in the UE.
//
// A downlink packet no rule covers gets QFI 0, the default flow; an uplink packet
// no rule covers is left unclassified, which lets reflective QoS or the default
// DRB take over (see ~QosFlowClassifier). The dlQfiRules default value,
// [{dscpAsQfi: true}], is plain DSCP-as-QFI assignment at every tunnel entry.
// Overriding either parameter replaces its whole table, so a configuration that
// scopes rules to one node (say, a MEC host's UPF) and still wants the DSCP
// classification elsewhere appends the catch-all back explicitly. Base stations
// are not delivery sites -- no SMF installs classification rules into a gNB -- and
// their filters classify unattributed traffic by a built-in DSCP-as-QFI residual
// (see ~TrafficFlowFilter).
//
simple BearerConfigurator
{
    parameters:
        string binderModule = default("binder");
        object staticDrbs = default([]);  // JSON array: [{coreNetwork, ue, drbId, profile, mappedQfis, filters, lcg, rlcMode, legs, pduSessionType, upperProtocol, isDefault, suppressSdapHeader, gbr, packetDelayBudget, packetErrorRate, qosPriorityLevel}, ...]; see banner comment for details
        object onDemandDrbs = default([  // JSON array, staticDrbs schema minus "drbId" (and "ue" optional): bearers created when traffic first matches them; the default value lets both stack kinds run unauthored; see banner comment for details
                {coreNetwork: "epc", filters: ["VoIP*"], lcg: 0, rlcMode: "UM"},
                {coreNetwork: "epc", filters: ["gaming*"], lcg: 2, rlcMode: "UM"},
                {coreNetwork: "epc", filters: ["VoDPacket*", "VoDFinishPacket*"], lcg: 1, rlcMode: "UM"},
                {coreNetwork: "epc", isDefault: true, lcg: 3, rlcMode: "UM"},
                {coreNetwork: "5gc", isDefault: true, suppressSdapHeader: true, lcg: 3, rlcMode: "UM"}
            ]);
        object drbProfiles = default({});  // JSON map of named field groups referenced by the staticDrbs entries' "profile" field, e.g. {voice: {rlcMode: "UM", gbr: true, ...}, ...}; see banner comment

        // QFI classification rules, delivered to their evaluation sites (see banner comment)
        object dlQfiRules = default([{dscpAsQfi: true}]);  // JSON array of downlink QFI-assignment rules [{node, filter, qfi|dscpAsQfi}, ...], delivered to the traffic flow filters at core-network tunnel entries; first match wins per site
        object ulQfiRules = default([]);  // JSON array of uplink QFI-assignment rules [{ue, filter, qfi|dscpAsQfi}, ...], delivered to the UEs' QoS-flow classifiers; [] = classify nothing

        // QoS-derived RAN defaults for definitions that do not state rlcMode/lcg themselves
        // (operator policy, not spec-mandated: 3GPP standardizes the QoS characteristics,
        // the RAN chooses what to make of them)
        double amPerThreshold = default(1e-4);  // rlcMode derivation: a definition whose QoS profile has packetErrorRate <= this gets "AM", else "UM"
        object lcgPriorityBounds = default([25, 50, 75]);  // Lcg derivation: qosPriorityLevel < bounds[k] -> LCG k, else LCG 3; strictly ascending, one bound between each pair of adjacent LCGs
        @display("i=block/cogwheel");
}