linux OCUDU 项目介绍-10(MAC层总体介绍--1)
1. MAC(媒体访问控制层)
MAC的主要职责包括:
- 对通过FAPI接口收发的MAC PDU进行编码和解码。
- 通过嵌入式gNB调度器,为系统信息、寻呼、UE数据(RLC PDU + MAC CE)和随机接入调度DL/UL授权。
- 将解码后的MAC Rx SDU解复用并转发至相应的逻辑信道。
- 处理接收到的MAC CE。
- PRACH处理和RNTI分配。
2. 架构

MAC与FAPI、RLC和DU控制平面交互。它由上述子组件构成,并通过抽象C++接口(include/ocudu/mac/)对外暴露功能;顶层MAC接口(mac.h)通过get_slot_handler()、get_pdu_handler()、get_cell_manager()和get_ue_configurator()等访问器提供每小区和全局处理器。三个对等实体对应图中的边缘:DU控制平面配置MAC,SDU与RLC交换,PDU通过FAPI交换。
3. 子组件
- MAC控制器(mac_controller) — 将DU配置请求(添加小区、添加/重配置/删除UE)转换为对其他子组件的命令,以最小的服务中断和无竞争的方式应用(参见配置生命周期)。
- RACH处理器(rach_handler) — 为接收到的PRACH前导码分配RNTI,并将每个RNTI与DU UE索引关联(参见RNTI管理)。
- MAC上行处理器(mac_ul_processor) — 解码接收到的MAC PDU,并解复用SDU和MAC CE(参见上行数据路径)。
- MAC下行处理器(mac_dl_processor) — 驱动调度器并组装下行MAC PDU(参见下行数据路径和调度器)。
4. DU控制平面接口
- 配置和UE生命周期事件,由DU管理器驱动:
- 配置 — mac_cell_manager(add_cell/remove_cell,以及每小区的start/stop/reconfigure)和mac_ue_configurator(handle_ue_create_request/..._reconfiguration_request/..._delete_request,以async_task形式返回)。
- UL-CCCH/竞争解决 — mac_ul_ccch_notifier(on_ul_ccch_msg_received、on_crnti_ce_received)向高层报告接收到的Msg3,触发DU中UE的创建。
5. RLC接口
用户平面SDU,每个承载对应一个逻辑信道,通过mac_logical_channel_config绑定:
- 输入(来自RLC):mac_sdu_tx_builder提供下行SDU(on_new_tx_sdu)用于下行PDU组装,以及RLC承载的缓冲区占用报告(on_buffer_state_update),MAC将其转发给调度器。
- 输出(到RLC):mac_sdu_rx_notifier(on_new_sdu),MAC用它向RLC转发解码后的上行SDU。
6. FAPI接口
MAC下边缘的处理器由FAPI适配器转换为真实的FAPI消息(FAPI适配器位于lib/mac之外),因此MAC纯粹基于这些抽象处理器编写。
6.1 输入(来自FAPI):
- mac_cell_slot_handler — 提供每时隙定时触发(handle_slot_indication),驱动调度和该时隙DL/UL结果的生成;同时呈现低层处理错误(handle_error_indication)和小区停止完成(handle_stop_indication)。
- mac_cell_rach_handler — 提供L1检测到的PRACH前导码(handle_rach_indication),启动随机接入过程。
- mac_cell_control_information_handler — 提供L1解码的上行控制反馈并转发给调度器:PUSCH解码结果(handle_crc)、携带SR/HARQ-ACK/CSI的PUCCH/PUSCH UCI(handle_uci)以及SRS信道报告(handle_srs)。
- mac_pdu_handler — 提供解码后的上行MAC PDU(handle_rx_data_indication),用于上行数据路径中的解码和解复用。
6.2 输出(到FAPI):
MAC通过mac_cell_result_notifier(从mac_result_notifier::get_cell获取)推送每时隙结果:
- on_new_downlink_scheduler_results — 下行调度决策(编码的PDCCH DCI、SSB和PDSCH分配),即DL_TTI.request。
- on_new_downlink_data — 组装后的下行MAC PDU载荷(SI、RAR、寻呼、UE DL-SCH),即Tx_Data.request。
- on_new_uplink_scheduler_results — 上行授权(PUSCH/PUCCH),即UL_TTI.request。
- on_cell_results_completion — 时隙结束哨兵,表示该时隙的所有结果已交付。
7. 并发与并行
MAC自身不拥有任何线程。每个MAC任务都在构造时提供的task_executor上运行,任务到执行器的映射决定了MAC的并发模型。这使得相同的MAC代码可以在测试和模拟器中单线程运行,或者在实际部署中通过仅更换执行器映射器分布到工作线程池上。
执行器通过mac_config以三个句柄提供给MAC:
- ctrl_exec — 单一的DU级控制执行器。
- cell_exec_mapper(mac_cell_executor_mapper)— 每小区执行器。
- ue_exec_mapper(mac_ue_executor_mapper)— 每UE执行器。
8. 外部事件与线程安全
MAC的公共入口点由其不控制的线程调用:时隙指示、RACH指示、CRC/UCI/SRS指示和接收的PDU都在FAPI线程上到达,而配置请求在DU管理器的线程上到达。这些调用者不直接接触MAC或调度器状态。每个入口点要么:
- 将事件分发到MAC执行器上——例如,时隙指示入队到小区的slot_ind_executor,接收的上行PDU入队到UE的mac_ul_pdu_executor——使得实际处理在所属strand上串行运行;或者
- 将事件转发给调度器,调度器在内部管理自己的线程安全。CRC、UCI、SRS和错误指示从调用线程直接传入调度器;调度器将其缓冲在自己的线程安全队列中,并在小区的slot_indication()上下文中稍后应用。
这是MAC并发模型的核心不变量:任何状态变更必须到达所属strand(或调度器的内部队列)后才能接触共享状态。如果一个新的入口点在调用者线程上内联读写MAC/调度器状态,而不是跳转到适当的执行器或延迟到调度器,就会引入数据竞争。
9. 串行化与并行性
MAC依赖strand(参见support/executors/strand_executor.h)而非锁来保持共享状态一致。strand保证分发到其上的任务逐个串行运行,即使strand由多线程工作池支持也是如此。因此,并行性在strand之间实现,而非在单个strand内部:不同strand上的任务可以在不同工作线程上并发运行,而同一strand上的任务从不重叠。
这产生了三个独立的并行轴:
- 跨小区 — 每个小区有自己的strand,因此不同小区并行调度和组装其DL/UL授权。
- 跨UE — UE分布在有界的strand集合上,因此不同UE的上行PDU处理可以并发进行。
- 控制与数据 — 控制平面重配置被汇集到其自己的串行执行器上,与每小区实时路径解耦。
相反,不能竞争的工作被强制放在同一strand上,从而被串行化。
10. 每小区执行
每个小区通过mac_cell_executor_mapper暴露两个执行器:
slot_ind_executor(cell) — 高优先级路径,用于来自FAPI的周期时隙指示。
mac_cell_executor(cell) — 默认路径,用于其他非时隙小区任务。
时隙指示是小区的心跳:mac_cell_processor::handle_slot_indication()仅将其入队到slot_ind_executor,实际工作——调用该小区的调度器、组装DL/UL PDU并将结果转发给FAPI——在该执行器的上下文中运行。因此,调度器没有自己的执行器;它在小区strand上每小区每时隙同步驱动一次。由于每个小区使用不同的strand,不同小区的调度并行运行,而单个小区内的一切都是串行的。
小区执行器可以以两种方式配置(du_high_executor_config::cell_executor_config):
- 每小区专用工作线程 — 每个小区拥有自己的线程,完全隔离小区。
- 基于strand的工作池 — 每小区一个strand,所有strand共享一个公共工作池。时隙指示使用比其他小区任务更高的strand优先级,因此不会被低优先级工作饿死。
11. 每UE执行
UE特定的工作运行在mac_ue_executor_mapper上:
- ctrl_executor(ue) — UE状态变更(创建、重配置、删除);不频繁。
- mac_ul_pdu_executor(ue) — 接收的MAC PDU解码和上行SDU解复用。
UE被映射到有界的strand池上(策略为per_cell或round_robin,受max_nof_strands限制),在并行性和内存之间进行权衡。在UE的strand内,控制任务优先于上行PDU处理,上行PDU处理又优先于下行PDU处理。不同strand上的两个UE并发处理其上行PDU;共享同一strand的两个UE则被串行化。
12. 控制平面串行化
来自DU管理器的配置请求(添加小区、添加/重配置/删除UE)由MAC控制器在单一的DU级ctrl_exec(串行strand)上处理。将所有重配置路由通过一个strand,使得MAC控制器能够无锁且不与每小区实时路径竞争地应用变更——它在明确定义的时点(例如小区激活/停用)与小区执行器交接,而不是直接变更小区状态。
13. 总结表
任务 执行器 范围 串行化范围 并行运行范围
时隙指示、调度、DL PDU组装 slot_ind_executor 每小区 一个小区内 跨小区
其他小区任务(低优先级) mac_cell_executor 每小区 一个小区内 跨小区
上行PDU解码/解复用 mac_ul_pdu_executor 每UE 一个UE的strand内 不同strand上的UE
UE控制(添加/重配置/删除) ctrl_executor 每UE 一个UE的strand内 不同strand上的UE
MAC配置(小区、UE) ctrl_exec DU级 整个MAC 无(完全串行)
14. 下行数据路径
下行路径由每小区时隙指示驱动。mac_cell_processor::handle_slot_indication_impl()每小区每时隙运行一次,执行以下操作:
- 调用该小区的调度器,获取sched_result。
- assemble_dl_sched_request()构建mac_dl_sched_result——SSB(ssb_helper)和编码的PDCCH DCI(encode_dci)——并通过on_new_downlink_scheduler_results转发给FAPI。
- assemble_dl_data_request()构建mac_dl_data_result,即实际的MAC PDU载荷,并通过on_new_downlink_data转发:
- SIB/广播通过sib_pdu_assembler,
- RAR通过rar_pdu_assembler,
- UE DL-SCH通过dl_sch_pdu_assembler,
- 寻呼通过paging_pdu_assembler。
- 上行授权通过on_new_uplink_scheduler_results转发,on_cell_results_completion关闭该时隙。
DL-SCH组装(dl_sch_pdu_assembler::assemble_newtx_pdu)分配HARQ缓冲区,对每个被调度的逻辑信道,从RLC拉取SDU(mac_sdu_tx_builder::on_new_tx_sdu)并编码子头和载荷;UE竞争解决标识和定时提前命令等MAC CE被复用进去,传输块被填充。重传(assemble_retx_pdu)重用缓存的HARQ缓冲区,而非重新获取SDU。一旦结果交给FAPI,update_logical_channel_dl_buffer_states()读取新的RLC缓冲区状态(on_buffer_state_update)并反馈给调度器(handle_dl_buffer_state_update)。
15. 上行数据路径
接收的PDU通过mac_pdu_handler::handle_rx_data_indication()(mac_ul_processor)进入。对每个PDU,通过RNTI表解析UE,并将工作分发到该UE的mac_ul_pdu_executor上,在那里pdu_rx_handler::handle_rx_pdu()运行:
- UL-SCH PDU被解包为subPDU(mac_ul_sch_pdu::unpack)。
- SDU被转发到逻辑信道的RLC承载(mac_sdu_rx_notifier::on_new_sdu)。
- MAC CE被解析并转发:BSR通过handle_ul_bsr_indication,PHR通过handle_ul_phr_indication,两者都由调度器消费。
- CCCH(Msg3/SRB0)——当TC-RNTI尚不存在对应UE时,UL-CCCH消息通过mac_ul_ccch_notifier::on_ul_ccch_msg_received传递给高层;一旦DU创建了UE(push_ul_ccch_msg),SDU本身被推送。
- C-RNTI CE — handle_crnti_ce()解析携带的C-RNTI对应的现有UE,将剩余subPDU重新分发到该UE的执行器上,并通知调度器(handle_crnti_ce_indication)和高层(on_crnti_ce_received)进行竞争解决。
16. 调度器
MAC包含gNB调度器,但将其视为ocudu_scheduler_adapter(实现mac_scheduler_adapter)背后的自包含子系统。MAC向调度器推送事件——rach_indication、CRC/UCI/SRS、BSR/PHR、下行缓冲区状态以及UE添加/重配置/删除——并通过slot_indication()每小区每时隙查询一次,其返回的sched_result驱动上述下行数据路径。如并发部分所述,调度器管理自己的指示接收线程安全。其内部设计在lib/scheduler/README.md中单独记录。
17. 配置生命周期
- 配置由MAC控制器(mac_controller)在ctrl_exec上处理。添加小区时,将其注册到时序源、指标、调度器和下行处理器。小区删除按相反顺序撤销这些步骤。MAC小区启动/停止控制调度器小区激活/停用。
- UE添加、重配置和删除是异步过程(ue_creation_procedure、ue_reconfiguration_procedure、mac_ue_removal_procedure),以协程形式实现,在控制执行器和每小区/每UE执行器之间跳转,建立或拆除下行和上行上下文。分发到每小区/每UE执行器的这些操作应具有延迟上界,以免影响在这些执行器中运行的其他延迟敏感任务。
- MAC和整个DU中的UE创建被延迟到Msg3(参见RA过程)。删除首先删除调度器上下文——因此不再产生授权——然后删除上行/下行上下文,最后删除控制器的UE条目。
18. RNTI管理
rnti_manager为每个检测到的基于竞争的PRACH前导码分配TC-RNTI,并为高层过程(例如F1AP UE Context Setup Request)创建的UE分配C-RNTI。rnti_value_table以无锁方式映射RNTI ↔ du_ue_index。
19. 无线链路失败检测
rlf_detector(由调度器适配器拥有)跟踪三个每UE原子计数器:连续下行KO(HARQ-ACK NACK/DTX)、上行KO(PUSCH CRC失败)和未解码CSI(DTX)。阈值来自mac_expert_cell_config(max_consecutive_dl_kos、max_consecutive_ul_kos、max_consecutive_csi_dtx,默认100)。handle_ack/handle_crc/handle_csi——由UCI解码器和CRC处理器驱动——在成功时重置相应计数器,在失败时递增;当计数器首次达到阈值时,通过mac_ue_radio_link_notifier::on_rlf_detected向DU管理器报告RLF,延迟到ctrl_exec上执行。接收到的C-RNTI MAC CE重置所有计数器并调用on_crnti_ce_received,在UE重新同步后取消虚假的RLF。
20. 过程
MAC运行时过程(例如随机接入)的分步描述在procedures.md中单独记录。
21. 总结
本文档描述了一个5G NR gNB(gNodeB)中MAC层的软件架构设计。MAC层是无线协议栈中的关键组成部分,负责管理无线资源的调度和数据的收发。
21.1 核心职责:
MAC层主要负责MAC PDU的编解码、上下行调度(包括系统信息、寻呼、用户数据和随机接入)、SDU的解复用与转发、MAC控制元素处理以及PRACH处理和RNTI分配。
21.2 架构特点:
- 模块化设计:MAC由MAC控制器、RACH处理器、上行处理器和下行处理器四个子组件构成,通过抽象C++接口与FAPI、RLC和DU控制平面交互。
- 并发模型:MAC自身不拥有线程,所有任务在外部提供的执行器上运行。采用strand(串行执行单元)而非锁来保证线程安全,实现了三个并行轴:跨小区、跨UE以及控制与数据分离。
- 数据路径:下行路径由时隙指示驱动,包括调度器调用、PDCCH/PDSCH组装和MAC PDU生成;上行路径处理接收的PDU,解包并分发SDU和MAC CE。
- 配置生命周期:配置操作在单一控制执行器上串行处理,UE的创建/重配置/删除以异步协程方式实现,确保与实时路径无竞争。

浙公网安备 33010602011771号