InfiniBand / RDMA 심화
InfiniBand 서브넷 아키텍처, RDMA 핵심 개념(QP, CQ, MR), 커널 Verbs API, 사용자 공간 라이브러리(libibverbs, librdmacm), IPoIB, 상위 프로토콜(SRP, iSER, NVMe-oF RDMA), GPUDirect RDMA, 성능 최적화 및 트러블슈팅 종합 가이드. 커널 내부 데이터 경로, 핵심 자료구조/API, 운영 환경 튜닝 포인트와 장애 디버깅 절차까지 실무 관점으로 다룹니다.
핵심 요약
- HCA — RDMA 엔진, DMA, QP/CQ를 가진 InfiniBand NIC입니다.
- QP — 송신/수신 작업이 실제로 적재되는 하드웨어 큐 쌍입니다.
- CQ — 완료 이벤트를 회수하는 큐이며 지연과 CPU 사용률을 좌우합니다.
- MR / rkey — 원격 접근 가능한 메모리와 그 접근 권한입니다.
- SM / SA — 패브릭에 LID와 경로를 배포하고 파티션 정책을 관리합니다.
단계별 이해
- 패브릭 준비
포트가Active이고 SM이 살아 있으며 LID/GID/P_Key가 정상 배포됐는지 확인합니다. - 리소스 생성
프로세스는 PD, MR, CQ, QP를 만들고 버퍼를 등록합니다. - 경로 확정
QPN/LID/GID/PSN을 교환하거나librdmacm으로 경로를 해석해 QP를 RTS까지 올립니다. - 데이터 전송
WR을 post하고 CQ를 poll하여 Send, RDMA Write/Read, Atomic을 실행합니다. - 스케일링
SRQ/XRC/DC, NUMA 배치, AR/QoS, GPU 메모리 연동으로 대규모 성능을 끌어올립니다.
InfiniBand 개요
InfiniBand(IB)는 고성능 컴퓨팅(HPC), 데이터센터, 스토리지 인터커넥트를 위해 설계된 고대역폭·저지연 네트워크 기술입니다. RDMA(Remote Direct Memory Access)를 네이티브로 지원하여 커널 바이패스, 제로카피, 프로토콜 오프로드를 통해 전통적인 TCP/IP 소켓 대비 극적인 성능 향상을 제공합니다.
이 문서는 네이티브 InfiniBand 패브릭을 중심으로 설명합니다. 같은 Verbs API를 쓰더라도
link_layer가 Ethernet이면 RoCE 계열이며, 이 경우 손실 모델, 혼잡 제어, 운영 도구, 장애 지점이 달라집니다.
따라서 실무에서는 먼저 장비가 정말 InfiniBand 포트인지, 아니면 Ethernet 포트에서 RDMA를 수행하는지부터 구분해야 합니다.
InfiniBand vs Ethernet 비교
| 특성 | InfiniBand | Ethernet (RoCE v2) | iWARP |
|---|---|---|---|
| RDMA 지원 | 네이티브 | RoCE v1/v2 (컨버전스) | TCP 위에 RDMA |
| 전송 계층 | IB Transport (신뢰성 내장) | UDP/IP (RoCE v2) | TCP/IP |
| 최대 대역폭 | 공개 규격상 XDR 800Gb/s급 이상으로 확장 | 800GbE급까지 확장 | 상용 생태계는 제한적 |
| 지연시간 | ~0.5 μs (HCA-to-HCA) | ~1–2 μs | ~5–10 μs |
| 손실 처리 | 신용 기반 흐름 제어 (Lossless) | PFC/ECN 필요 (Lossless 구성) | TCP 재전송 |
| 서브넷 관리 | Subnet Manager (opensm) | 표준 이더넷 스위칭 | 표준 이더넷 스위칭 |
| 주요 사용처 | HPC, AI/ML 클러스터, 스토리지 | 데이터센터, 클라우드 | 엔터프라이즈 스토리지 |
RDMA 전송 기술 비교
| 기술 | 하위 계층 | 라우팅 | Lossless 요구 | 특징 |
|---|---|---|---|---|
| IB Native RDMA | InfiniBand L2 | IB 서브넷 라우팅 | 내장 (Credit-based) | 최저 지연, HPC 표준 |
| RoCE v1 | Ethernet L2 | L2 전용 | PFC 필수 | 같은 VLAN 내에서만 동작 |
| RoCE v2 | UDP/IP | IP 라우팅 가능 | PFC + ECN 권장 | L3 라우팅, 데이터센터 표준 |
| iWARP | TCP/IP | IP 라우팅 가능 | 불필요 (TCP 재전송) | Lossy 네트워크 호환, 높은 지연 |
InfiniBand 서브넷 아키텍처
서브넷 구성 요소
InfiniBand 서브넷은 다음 구성 요소로 이루어집니다:
- HCA (Host Channel Adapter): 호스트에 장착되는 InfiniBand NIC. 각 HCA는 1~2개의 물리 포트를 가지며, 각 포트가 서브넷에 연결됩니다. RDMA 엔진, DMA 엔진, QP/CQ 하드웨어 큐를 내장합니다.
- Switch: IB 패킷을 LID(Local ID) 기반으로 포워딩하는 L2 스위치. 서브넷 내부 통신을 담당하며, 포워딩 테이블은 Subnet Manager가 설정합니다.
- Router: 서로 다른 서브넷 간 GID 기반 L3 라우팅을 수행합니다.
- Subnet Manager (SM): 서브넷의 중앙 관리자. 토폴로지 탐색, LID 할당, 경로 계산, 포워딩 테이블 배포, QoS 설정 등을 수행합니다. 보통 전용 노드 또는 스위치 내장 SM을 사용하며, standby SM으로 HA를 구성합니다.
물리 계층 및 속도
| 세대 | lane 신호 속도 | 대표 포트 속도 | 주요 링크 폭 | 비고 |
|---|---|---|---|---|
| SDR | 2.5 Gbaud | 4X 기준 8 Gb/s | 1X / 4X / 12X | 초기 세대, 8b/10b |
| DDR | 5 Gbaud | 4X 기준 16 Gb/s | 1X / 4X / 12X | 8b/10b |
| QDR | 10 Gbaud | 4X 기준 32 Gb/s | 1X / 4X / 12X | 오랫동안 HPC 표준 |
| FDR | 14.0625 Gbaud | 4X 기준 54.54 Gb/s | 4X / 10X | 64b/66b 도입 |
| EDR | 25 Gbaud | 4X 기준 100 Gb/s | 1X / 2X / 4X | 현대 세대의 출발점 |
| HDR | 50 Gbaud | HDR100(2X), HDR200(4X) | 2X / 4X | PAM4 |
| NDR | 100 Gbaud | NDR200(2X), NDR400(4X) | 2X / 4X | PAM4 |
| XDR | 200 Gbaud | XDR800(4X), 스위치 간 1.6 Tb/s급 링크 지원 | 4X / 8X | 최신 공개 세대 |
주소 체계
- LID (Local Identifier): 16비트, 서브넷 내 고유 주소. Subnet Manager가 할당합니다. 유니캐스트 LID 범위: 0x0001~0xBFFF, 멀티캐스트: 0xC000~0xFFFE.
- GID (Global Identifier): 128비트, IPv6 형식의 글로벌 주소. 서브넷 간 라우팅에 사용됩니다.
Subnet Prefix (64bit) + GUID (64bit)로 구성됩니다. - GUID (Globally Unique Identifier): 64비트, 제조사가 부여하는 고유 식별자. Node GUID, Port GUID, System Image GUID가 있습니다.
- P_Key (Partition Key): 16비트, IB 서브넷 내 논리적 파티션 구분. 이더넷의 VLAN과 유사한 개념으로, 같은 P_Key를 가진 노드끼리만 통신할 수 있습니다.
링크 계층, 경로 선택, QoS
InfiniBand는 단순히 "빠른 NIC"가 아니라, 패브릭 수준에서 경로와 서비스 클래스를 제어하는 링크 계층을 내장합니다. 애플리케이션은 QP를 만들고 WR을 post하지만, 실제 패킷은 SA가 돌려준 Path Record와 SM이 배포한 SL/VL 정책에 따라 흐릅니다.
- Path MTU: 경로별 MTU는 보통 256, 512, 1024, 2048, 4096 바이트 중 하나이며, RC/UC QP의
path_mtu설정은 상대 포트/경로의 지원 범위를 넘을 수 없습니다. - SL (Service Level): 서비스 등급입니다. 애플리케이션이나 ULP가 직접 또는 간접으로 선택하며, SM이 QoS 정책과 함께 배포합니다.
- VL (Virtual Lane): 한 물리 링크를 여러 논리 레인으로 분리해 혼잡을 완화합니다. 실무에서는 데이터 트래픽과 관리 트래픽을 서로 다른 레인 정책으로 취급합니다.
- Credit-based Flow Control: 수신 버퍼 크레딧이 없으면 송신이 멈추므로, 네이티브 IB는 별도의 PFC 없이도 무손실 특성을 유지합니다.
- LMC / 다중 경로: 하나의 포트에 여러 경로 비트를 부여해 동일 엔드포인트 사이에도 여러 포워딩 경로를 만들 수 있습니다.
ibv_post_send() 호출부만 보지 말고, 해당 연결의 Path MTU, SL, P_Key, LID 경로, AR 설정까지 함께 봐야 합니다.
InfiniBand의 병목은 소켓 버퍼보다도 경로 정책과 패브릭 큐 배치에서 자주 발생합니다.
관리 평면: SM, SA, MAD, CM
InfiniBand의 관리 평면은 데이터 평면과 분리되어 있습니다. 패브릭이 처음 올라올 때는 SM(Subnet Manager)이 토폴로지를 스캔하고, 각 포트에 LID를 부여하고, 스위치의 포워딩 테이블을 채웁니다. 이후 애플리케이션과 ULP는 SA(Subnet Administration)에 Path Record, 멀티캐스트 그룹, 파티션 정보를 질의합니다.
- MAD (Management Datagram): 관리 패킷 포맷입니다. SM/SA/성능 카운터 질의 등 제어 트래픽이 여기에 실립니다.
- QP0 / QP1: QP0는 Subnet Management 패킷용, QP1은 일반 관리 서비스(GSI)용으로 쓰입니다. 데이터 QP와 별도입니다.
/dev/infiniband/umadX: 사용자 공간에서 MAD를 직접 송수신할 때 쓰는 문자 디바이스입니다.opensm, 진단 도구가 활용합니다./dev/infiniband/issmX: 로컬 포트의 IsSM capability bit를 제어해 해당 포트를 SM 후보로 다룰 때 사용합니다.- RDMA CM: 애플리케이션이 QPN/LID/GID/PSN 교환을 직접 하지 않도록 연결 설정을 자동화하는 계층입니다. 사용자 공간에서는
librdmacm이/dev/infiniband/rdma_cm을 통해 이 기능을 사용합니다.
핵심 자료구조 및 개념
Queue Pair (QP)
QP는 RDMA 통신의 기본 단위로, Send Queue (SQ)와 Receive Queue (RQ) 한 쌍으로 구성됩니다. 각 QP는 고유한 QP Number (QPN)를 가지며, 원격 QP와 1:1(RC), 1:N(UD) 등의 연결 관계를 맺습니다.
- SQ (Send Queue): 송신 측 Work Request(WR)를 큐잉하는 하드웨어 큐. RDMA Write, RDMA Read, Send, Atomic 등의 WR을 제출합니다.
- RQ (Receive Queue): 수신 측 Receive WR을 큐잉합니다. Send/Recv 모델에서 수신 버퍼를 미리 게시(post)해야 합니다.
- SRQ (Shared Receive Queue): 여러 QP가 공유하는 수신 큐. 수신 버퍼를 효율적으로 관리할 수 있습니다.
Completion Queue (CQ)
CQ는 WR의 완료 이벤트(Work Completion, WC)를 수신하는 큐입니다. 하나의 CQ를 여러 QP의 SQ/RQ에 공유할 수 있습니다. 완료 확인 방식으로 polling(busy-wait)과 completion channel(이벤트 기반) 두 가지를 지원합니다.
Memory Region (MR)
RDMA 동작에 사용할 메모리 영역을 HCA에 등록하는 객체입니다. 등록 시 물리 페이지가 핀(pin)되고, HCA가 DMA로 직접 접근할 수 있는 가상→물리 주소 변환 테이블이 생성됩니다.
- lkey (Local Key): 로컬 QP가 이 MR에 접근할 때 사용하는 키.
- rkey (Remote Key): 원격 QP가 RDMA Write/Read로 이 MR에 접근할 때 사용하는 키. rkey를 원격 측에 전달해야 RDMA 동작이 가능합니다.
고급 메모리 등록: ODP, MW, dma-buf
실무에서는 단순한 ibv_reg_mr()만으로는 부족한 경우가 많습니다. 대용량 메모리, GPU 메모리, 고빈도 권한 부여/회수 패턴을 처리하려면
메모리 등록 전략 자체를 따로 설계해야 합니다.
- ODP (On-Demand Paging):
IBV_ACCESS_ON_DEMAND플래그로 생성하는 MR입니다. 필요 시점에 페이지를 가져오므로 등록 시간이 짧고,ibv_advise_mr()로 prefetch 힌트를 줄 수 있습니다. - Memory Window (MW): MR 자체를 다시 등록하지 않고도 원격 접근 권한을 bind / invalidate로 동적으로 부여·회수합니다. type 2 MW는 WR 기반 invalidate가 가능해 동적 capability 모델에 적합합니다.
- dma-buf 기반 MR: 최신 사용자 공간은 dma-buf FD를 통해 외부 메모리 객체를 MR로 등록할 수 있습니다. GPU, DPU, 미디어 가속기 메모리를 같은 Verbs 모델에 연결할 때 유용합니다.
- UMR / 간접 mkey: mlx5 계열에서는 여러 산재 버퍼를 커널 개입 없이 간접 키로 재구성하는 UMR 경로를 제공해, SG가 많은 워크로드의 등록 오버헤드를 줄일 수 있습니다.
rkey는 사실상 "원격 DMA 접근 토큰"입니다. 데이터 버퍼 주소와 rkey를 애플리케이션 프로토콜에 평문으로 흘려보내면
그 자체가 capability 누출이 되므로, 제어 채널과 데이터 채널을 분리하고 무효화 시점을 설계해야 합니다.
Protection Domain (PD) / Address Handle (AH)
- PD (Protection Domain): QP, MR, CQ 등의 리소스를 논리적으로 격리하는 보호 도메인. 같은 PD 내의 리소스만 상호 접근 가능합니다.
- AH (Address Handle): UD QP에서 목적지 주소(LID/GID)를 캡슐화하는 객체. RC/UC QP는 연결 시 주소를 설정하므로 AH가 불필요합니다.
Work Request (WR) / Work Completion (WC)
- WR (Work Request): QP의 SQ 또는 RQ에 제출하는 작업 요청. Send, Recv, RDMA Write, RDMA Read, Atomic CAS/FAA 등의 유형이 있습니다. 각 WR은 하나 이상의 SGE (Scatter/Gather Element)로 데이터 버퍼를 지정합니다.
- WC (Work Completion): CQ에서 poll하여 얻는 완료 결과. 성공/실패 상태, 전송 바이트 수, 완료된 WR의 ID(
wr_id) 등을 포함합니다.
QP 상태 머신
QP는 엄격한 상태 전이 순서를 따라야 합니다:
RESET → INIT → RTR → RTS 순서로 전이해야 합니다.
INIT 단계에서 P_Key, 포트 번호, 접근 플래그를 설정하고,
RTR(Ready to Receive)에서 원격 QPN, LID/GID, PSN 등 수신 파라미터를 설정하며,
RTS(Ready to Send)에서 타임아웃, 재시도 횟수 등 송신 파라미터를 설정합니다.
순서를 건너뛰면 ibv_modify_qp()가 -EINVAL을 반환합니다.
ibv_reg_mr()는 물리 페이지를 핀(pin)하므로 대용량 메모리 등록 시 상당한 시간이 소요됩니다.
Mellanox/NVIDIA ConnectX HCA는 ODP (On-Demand Paging)을 지원하여 실제 접근 시점에 페이지를 핀하는 지연 등록을 제공합니다.
ibv_reg_mr() 시 IBV_ACCESS_ON_DEMAND 플래그를 지정하면 ODP가 활성화됩니다.
ODP는 등록 시간을 단축하지만, 첫 접근 시 페이지 폴트 오버헤드가 발생할 수 있습니다.
RDMA 동작 (Operations)
Send / Receive
양측 관여(two-sided) 동작입니다. 송신 측이 IBV_WR_SEND WR을 SQ에 post하면,
수신 측은 미리 RQ에 게시한 Receive WR의 버퍼로 데이터를 수신합니다.
수신 측 CPU가 반드시 관여해야 하므로 RDMA Write/Read 대비 오버헤드가 높지만,
메시지 도착을 수신 측이 즉시 인지할 수 있는 장점이 있습니다.
RDMA Write / RDMA Write with Immediate
단측 관여(one-sided) 동작입니다. 송신 측이 원격 MR의 주소(rkey + remote addr)를 지정하여 데이터를 직접 씁니다. 수신 측 CPU는 전혀 관여하지 않습니다 (커널 바이패스 + 제로카피). RDMA Write with Immediate는 32비트 즉시값(imm_data)을 함께 전달하며, 수신 측 RQ에서 완료 이벤트가 생성되어 데이터 도착을 알릴 수 있습니다.
RDMA Read
단측 관여 동작입니다. 로컬 측이 원격 MR에서 데이터를 읽어옵니다.
원격 MR의 rkey와 주소를 알아야 하며, 원격 측 CPU 개입 없이 HCA가 직접 처리합니다.
원격 MR에 IBV_ACCESS_REMOTE_READ 접근 권한이 설정되어 있어야 합니다.
Atomic 연산 (CAS, FAA)
- Compare and Swap (CAS): 원격 메모리의 64비트 값을 비교하여 일치하면 새 값으로 교체합니다. 분산 락 구현에 활용됩니다.
- Fetch and Add (FAA): 원격 메모리의 64비트 값에 지정한 값을 더하고 이전 값을 반환합니다. 분산 카운터에 활용됩니다.
Atomic 연산은 RC QP에서만 지원되며, 원격 MR에 IBV_ACCESS_REMOTE_ATOMIC 권한이 필요합니다.
연결 모드 — RC, UC, UD, XRC
| QP 타입 | 연결 방식 | 신뢰성 | 지원 동작 | MTU | 사용 사례 |
|---|---|---|---|---|---|
| RC | 연결 지향 (1:1) | 신뢰 (ACK/재전송) | Send, RDMA Write/Read, Atomic | 최대 4KB | 스토리지, 범용 RDMA |
| UC | 연결 지향 (1:1) | 비신뢰 (무 ACK) | Send, RDMA Write | 최대 4KB | 벌크 전송 (손실 허용) |
| UD | 비연결 (1:N) | 비신뢰 | Send 전용 | 최대 MTU (4KB) | 멀티캐스트, 관리 트래픽 |
| XRC | 연결 지향 (N:1 SRQ) | 신뢰 | Send, RDMA Write/Read, Atomic | 최대 4KB | 다수 프로세스 간 효율적 통신 |
스케일링 모델: SRQ, XRC, DC, Tag Matching
작은 클러스터에서는 RC QP를 peer 수만큼 만드는 단순 모델도 충분하지만, 대규모 MPI/AI/스토리지 환경에서는 QP와 RQ 상태가 급격히 늘어납니다. 그래서 RDMA 스택은 다음과 같은 스케일링 기법을 함께 사용합니다.
- SRQ: 여러 QP가 하나의 Receive Queue를 공유합니다. 대량 fan-in 서버에서 수신 버퍼 총량을 크게 줄일 수 있습니다.
- XRC: 수신 측 컨텍스트를 공유해 RC의 신뢰성은 유지하면서도 연결 수 증가에 따른 메모리 사용량을 억제합니다.
- DC (DCT/DCI): mlx5 계열의 동적 연결 전송입니다. 수많은 피어와 희소 통신을 해야 할 때 모든 피어마다 풀 RC 상태를 만들지 않고도 낮은 지연을 노릴 수 있습니다.
- Tag Matching Offload: MPI의 eager/rendezvous 패턴에서 예상 수신 큐와 unexpected message 리스트를 하드웨어/소프트웨어가 협력 관리하여 메시지 매칭 비용을 줄입니다.
RDMA 동작 비교
| 동작 | 방향 | 관여 측 | 수신 WR 필요 | 원격 rkey 필요 | CQ 완료 위치 |
|---|---|---|---|---|---|
| Send | 송신→수신 | 양측 (two-sided) | 예 | 아니오 | 송신 + 수신 CQ |
| RDMA Write | 로컬→원격 | 송신측만 (one-sided) | 아니오 | 예 | 송신 CQ만 |
| RDMA Write+Imm | 로컬→원격 | 양측 | 예 (imm 수신용) | 예 | 송신 + 수신 CQ |
| RDMA Read | 원격→로컬 | 로컬만 (one-sided) | 아니오 | 예 | 로컬 CQ만 |
| Atomic CAS | 원격 in-place | 로컬만 | 아니오 | 예 | 로컬 CQ만 |
| Atomic FAA | 원격 in-place | 로컬만 | 아니오 | 예 | 로컬 CQ만 |
리눅스 커널 InfiniBand 서브시스템
drivers/infiniband/ 소스 구조
ib_core 모듈
ib_core는 InfiniBand 서브시스템의 핵심 프레임워크입니다. HCA 드라이버가 ib_register_device()로 디바이스를 등록하면,
ib_core가 sysfs 항목 생성, 이벤트 알림, Verbs API 디스패치 등을 처리합니다.
모든 RDMA 디바이스(IB, RoCE, iWARP)가 동일한 Verbs 추상화를 통해 접근됩니다.
ib_uverbs / ib_umad
- ib_uverbs:
/dev/infiniband/uverbsN캐릭터 디바이스를 통해 사용자 공간에서 Verbs API를 사용할 수 있게 합니다. libibverbs가 이 인터페이스를 사용합니다. - ib_umad:
/dev/infiniband/umadN을 통해 사용자 공간에서 MAD(Management Datagram)를 송수신할 수 있게 합니다. opensm이 이 인터페이스를 사용합니다.
대표 모듈과 Kconfig
배포판 커널에서는 대부분 RDMA 기능이 모듈 형태로 제공됩니다. 현재 리눅스 메인라인 Kconfig와 rdma-core README를 기준으로, 실무에서 자주 만나는 항목만 추려 보면 다음과 같습니다.
| 역할 | 대표 모듈 | Kconfig / 소스 기준 | 비고 |
|---|---|---|---|
| RDMA 미들레이어 | ib_core |
menuconfig INFINIBAND |
Verbs 공통 프레임워크와 장치 등록 기반 |
| 사용자 공간 Verbs | ib_uverbs |
INFINIBAND_USER_ACCESS, INFINIBAND_USER_MEM 계열 |
/dev/infiniband/uverbsN 제공 |
| 주소 해석 계층 | ib_addr 계열 |
INFINIBAND_ADDR_TRANS |
GID, netdev 연동, 경로 해석 보조 |
| IPoIB | ib_ipoib |
INFINIBAND_IPOIB |
ib0 같은 netdev 제공 |
| Mellanox / NVIDIA HCA | mlx5_ib |
MLX5_INFINIBAND |
ConnectX 계열의 핵심 RDMA provider |
| Intel Omni-Path 계열 | hfi1 |
INFINIBAND_HFI1 |
대규모 HPC 설치에서 자주 보임 |
| 소프트웨어 RoCE | rdma_rxe |
RDMA_RXE |
Ethernet 기반 개발/랩 환경에 유용 |
| 소프트웨어 iWARP | siw |
RDMA_SIW |
TCP/IP 기반 RDMA 기능 검증용 |
주요 커널 구조체
/* include/rdma/ib_verbs.h - 핵심 구조체 (간략화) */
struct ib_device {
const char *name; /* 디바이스 이름 (mlx5_0 등) */
struct ib_device_ops ops; /* Verbs 콜백 함수 테이블 */
struct device dev; /* sysfs 디바이스 */
u32 phys_port_cnt; /* 물리 포트 수 */
struct ib_device_attr attrs; /* 디바이스 능력 (속성) */
struct list_head event_handler_list;
enum rdma_transport_type (*get_transport)(struct ib_device *, u32);
};
struct ib_qp {
struct ib_device *device;
struct ib_pd *pd; /* Protection Domain */
struct ib_cq *send_cq; /* 송신 Completion Queue */
struct ib_cq *recv_cq; /* 수신 Completion Queue */
struct ib_srq *srq; /* Shared Receive Queue (선택) */
u32 qp_num; /* QP Number */
enum ib_qp_type qp_type; /* RC, UC, UD, XRC 등 */
void (*event_handler)(struct ib_event *, void *);
};
struct ib_cq {
struct ib_device *device;
int cqe; /* CQ 엔트리 수 */
struct ib_uobject *uobject;
ib_comp_handler comp_handler; /* 완료 콜백 */
void *cq_context;
int comp_vector; /* IRQ 벡터 */
enum ib_poll_context poll_ctx; /* 폴링 컨텍스트 */
};
struct ib_mr {
struct ib_device *device;
struct ib_pd *pd;
u32 lkey; /* Local Key */
u32 rkey; /* Remote Key */
u64 iova; /* I/O Virtual Address */
u64 length; /* 등록된 메모리 길이 */
enum ib_mr_type type; /* MEM_REG, DMA, USER 등 */
};
커널 Verbs API
| 카테고리 | API 함수 | 설명 |
|---|---|---|
| 디바이스 | ib_register_device() | HCA 드라이버가 디바이스 등록 |
ib_query_device() | 디바이스 속성(포트 수, 최대 QP 수 등) 조회 | |
| PD | ib_alloc_pd() | Protection Domain 생성 |
ib_dealloc_pd() | PD 해제 | |
| QP | ib_create_qp() | QP 생성 (타입, CQ, SRQ 지정) |
ib_modify_qp() | QP 상태 전이 (RESET→INIT→RTR→RTS) | |
ib_destroy_qp() | QP 파괴 | |
| CQ | ib_alloc_cq() / ib_create_cq() | CQ 생성 |
ib_poll_cq() | CQ에서 완료 이벤트 폴링 | |
| MR | ib_reg_user_mr() | 사용자 공간 메모리 등록 |
ib_dereg_mr() | MR 해제 | |
| 데이터 전송 | ib_post_send() | SQ에 Work Request 게시 |
ib_post_recv() | RQ에 Receive WR 게시 |
커널 내부에서 QP를 생성하고 데이터를 전송하는 기본 흐름:
/* 커널 Verbs API 사용 예제 (간략화) */
struct ib_pd *pd;
struct ib_cq *cq;
struct ib_qp *qp;
/* 1. Protection Domain 생성 */
pd = ib_alloc_pd(ib_dev, 0);
/* 2. Completion Queue 생성 */
cq = ib_alloc_cq(ib_dev, NULL, 256, 0, IB_POLL_SOFTIRQ);
/* 3. Queue Pair 생성 */
struct ib_qp_init_attr qp_attr = {
.event_handler = my_qp_event,
.send_cq = cq,
.recv_cq = cq,
.cap = {
.max_send_wr = 128,
.max_recv_wr = 128,
.max_send_sge = 1,
.max_recv_sge = 1,
},
.qp_type = IB_QPT_RC,
};
qp = ib_create_qp(pd, &qp_attr);
/* 4. QP 상태 전이: RESET → INIT → RTR → RTS */
struct ib_qp_attr attr;
memset(&attr, 0, sizeof(attr));
attr.qp_state = IB_QPS_INIT;
attr.pkey_index = 0;
attr.port_num = 1;
attr.qp_access_flags = IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ;
ib_modify_qp(qp, &attr, IB_QP_STATE | IB_QP_PKEY_INDEX |
IB_QP_PORT | IB_QP_ACCESS_FLAGS);
/* RTR, RTS 전이도 유사하게 진행 ... */
/* 5. Work Request 게시 (RDMA Write) */
struct ib_sge sge = {
.addr = dma_addr,
.length = len,
.lkey = mr->lkey,
};
struct ib_send_wr wr = {
.opcode = IB_WR_RDMA_WRITE,
.send_flags = IB_SEND_SIGNALED,
.sg_list = &sge,
.num_sge = 1,
.wr.rdma = {
.remote_addr = remote_addr,
.rkey = remote_rkey,
},
};
const struct ib_send_wr *bad_wr;
ib_post_send(qp, &wr, &bad_wr);
/* 6. 완료 폴링 */
struct ib_wc wc;
while (ib_poll_cq(cq, 1, &wc) == 0)
/* busy wait */;
if (wc.status != IB_WC_SUCCESS)
pr_err("WC error: %d\\n", wc.status);
사용자 공간 라이브러리
libibverbs (ibv_* API)
libibverbs는 RDMA Verbs API의 사용자 공간 구현체입니다.
/dev/infiniband/uverbsN을 통해 커널의 ib_uverbs와 통신하며,
데이터 경로(post_send, poll_cq 등)는 메모리 매핑된 Doorbell/CQ를 통해 커널 바이패스로 동작합니다.
주요 API 함수:
ibv_get_device_list(): RDMA 디바이스 목록 조회ibv_open_device(): 디바이스 컨텍스트 열기ibv_alloc_pd(): Protection Domain 생성ibv_reg_mr(): Memory Region 등록ibv_create_cq()/ibv_create_cq_ex(): CQ 생성ibv_create_qp(): QP 생성ibv_modify_qp(): QP 상태 전이ibv_post_send()/ibv_post_recv(): WR 게시 (커널 바이패스)ibv_poll_cq(): CQ 폴링 (커널 바이패스)
librdmacm (rdma_* API)
librdmacm은 RDMA Connection Manager 라이브러리로, TCP 소켓과 유사한 연결 설정/해제 인터페이스를 제공합니다.
QP 상태 전이를 자동으로 처리하므로 개발이 훨씬 간편합니다.
rdma_create_id(): RDMA CM ID 생성 (소켓에 해당)rdma_resolve_addr(): IP → GID 주소 해석rdma_resolve_route(): 라우팅 경로 해석rdma_connect()/rdma_accept(): 연결 설정rdma_disconnect(): 연결 해제
rdma-core 패키지
rdma-core는 libibverbs, librdmacm, 벤더 플러그인(libmlx5, libirdma 등), 관리 도구를 통합한 오픈소스 패키지입니다.
대부분의 Linux 배포판에서 rdma-core 패키지로 설치할 수 있습니다.
# rdma-core 설치 (Ubuntu/Debian)
sudo apt install rdma-core libibverbs-dev librdmacm-dev
# rdma-core 설치 (RHEL/CentOS)
sudo dnf install rdma-core libibverbs-devel librdmacm-devel
/dev/infiniband/uverbsX— libibverbs가 PD/CQ/QP/MR 등 Verbs 객체를 생성하는 기본 경로/dev/infiniband/rdma_cm— librdmacm이 주소 해석, 경로 해석, 연결 이벤트를 처리하는 경로/dev/infiniband/umadX— opensm, saquery, 진단 도구가 MAD를 직접 보내는 경로/dev/infiniband/issmX— 특정 포트를 SM 후보로 다룰 때 IsSM capability bit를 제어하는 경로
Provider 확장 API: mlx5dv, DevX, CQE 최적화
표준 Verbs는 공통 기능을 제공하지만, 최고 성능 튜닝은 provider 확장에 들어 있는 경우가 많습니다.
특히 mlx5 계열은 mlx5dv_*와 DevX를 통해 표준 계층이 아직 추상화하지 못한 하드웨어 기능을 직접 노출합니다.
| 확장 경로 | 대표 기능 | 언제 쓰는가 | 주의점 |
|---|---|---|---|
mlx5dv_create_qp() |
DCT / DCI, 고급 QP 속성 | 대규모 희소 통신, MPI/AI collective 최적화 | mlx5 전용, 타 provider 이식성 낮음 |
mlx5dv_create_cq() |
CQE compression, mini-CQE 포맷 | 대량 완료 이벤트에서 PCIe/메모리 대역폭 절감 | 디코딩 경로가 복잡해지고 관측성도 낮아질 수 있음 |
| DevX | 펌웨어 객체 직접 생성/수정 | 표준 Verbs보다 더 낮은 수준의 HW 기능 제어 | 펌웨어 의존성이 높고 코드 유지보수 비용이 큼 |
상위 통신 스택: UCX, Open MPI, libfabric
실제 HPC/AI 애플리케이션은 보통 ibv_post_send()를 직접 호출하지 않습니다. 대부분은
MPI, PGAS, RPC, collective 라이브러리가 UCX 또는 libfabric(OFI) 같은 중간 계층을 통해
Verbs와 provider 확장을 선택합니다.
| 계층 | 역할 | InfiniBand 문맥에서 중요한 점 |
|---|---|---|
| UCX | 전송 선택, 프로토콜 분할, multi-rail, GPU 메모리 연동 | UCX_TLS로 rc, dc, cuda, rocm 조합을 제어하며, UCX_LOG_LEVEL=info로 실제 transport 선택을 볼 수 있습니다. |
| Open MPI | MPI point-to-point, collective, RMA | Open MPI v6.1.x 문서는 InfiniBand/RoCE를 UCX PML 경로로 지원하고, 과거 openib BTL은 더 이상 포함하지 않는다고 명시합니다. |
| libfabric / OFI | provider 기반 통신 추상화 | verbs provider는 libibverbs, librdmacm 위에 올라가며 FI_EP_RDM은 보통 verbs;ofi_rxm 형태로 layering 됩니다. |
# UCX가 실제로 어떤 transport를 선택했는지 확인
ucx_info -d
UCX_LOG_LEVEL=info mpirun -x UCX_TLS=rc -x UCX_NET_DEVICES=mlx5_0:1 ./app
# Adaptive Routing이 켜진 SL을 UCX가 고르도록 시도
mpirun -x UCX_IB_AR_ENABLE=yes -x UCX_IB_SL=1 ./app
# Open MPI에서 UCX 경로를 명시
mpirun --mca pml ucx -x UCX_NET_DEVICES=mlx5_0:1 ./app
개발용 소프트웨어 RDMA 랩
네이티브 InfiniBand 장비가 없어도 RDMA 프로그래밍 모델 자체는 연습할 수 있습니다.
rdma-core README는 rdma_rxe와 siw를 사용해 기존 NIC 위에 소프트웨어 RDMA 장치를 추가하는 방식을 안내합니다.
# Soft-RoCE (RXE) 예시
modprobe rdma_rxe
rdma link add rxe0 type rxe netdev eth0
# 소프트웨어 iWARP (SIW) 예시
modprobe siw
rdma link add siw0 type siw netdev eth0
# 장치 확인
rdma link
ibv_devices
rxe와 siw는 Verbs 실험과 기능 검증에는 좋지만, 네이티브 InfiniBand 패브릭의 지연·혼잡·SM/SA·credit-based flow control 특성을 재현하지는 못합니다.
이들은 API/상태머신 학습용으로 이해하는 편이 정확합니다.
코드 예제 — RDMA RC Send/Recv
/* libibverbs RC Send/Recv 전체 흐름 (간략화) */
#include <infiniband/verbs.h>
int main(void)
{
struct ibv_device **dev_list;
struct ibv_context *ctx;
struct ibv_pd *pd;
struct ibv_mr *mr;
struct ibv_cq *cq;
struct ibv_qp *qp;
char buf[4096];
/* 1. 디바이스 열기 */
dev_list = ibv_get_device_list(NULL);
ctx = ibv_open_device(dev_list[0]);
/* 2. PD, MR, CQ 생성 */
pd = ibv_alloc_pd(ctx);
mr = ibv_reg_mr(pd, buf, sizeof(buf),
IBV_ACCESS_LOCAL_WRITE |
IBV_ACCESS_REMOTE_WRITE |
IBV_ACCESS_REMOTE_READ);
cq = ibv_create_cq(ctx, 16, NULL, NULL, 0);
/* 3. QP 생성 */
struct ibv_qp_init_attr qp_init = {
.send_cq = cq,
.recv_cq = cq,
.cap = { .max_send_wr = 16, .max_recv_wr = 16,
.max_send_sge = 1, .max_recv_sge = 1 },
.qp_type = IBV_QPT_RC,
};
qp = ibv_create_qp(pd, &qp_init);
/* 4. QP 상태 전이: RESET → INIT → RTR → RTS */
struct ibv_qp_attr attr;
memset(&attr, 0, sizeof(attr));
/* INIT */
attr.qp_state = IBV_QPS_INIT;
attr.pkey_index = 0;
attr.port_num = 1;
attr.qp_access_flags = IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_REMOTE_READ;
ibv_modify_qp(qp, &attr,
IBV_QP_STATE | IBV_QP_PKEY_INDEX | IBV_QP_PORT | IBV_QP_ACCESS_FLAGS);
/* RTR — 원격 QPN, LID, GID, PSN 필요 (out-of-band 교환) */
attr.qp_state = IBV_QPS_RTR;
attr.path_mtu = IBV_MTU_4096;
attr.dest_qp_num = remote_qpn; /* 상대방 QPN */
attr.rq_psn = 0;
attr.max_dest_rd_atomic = 1;
attr.min_rnr_timer = 12;
attr.ah_attr.dlid = remote_lid;
attr.ah_attr.port_num = 1;
ibv_modify_qp(qp, &attr,
IBV_QP_STATE | IBV_QP_AV | IBV_QP_PATH_MTU |
IBV_QP_DEST_QPN | IBV_QP_RQ_PSN |
IBV_QP_MAX_DEST_RD_ATOMIC | IBV_QP_MIN_RNR_TIMER);
/* RTS */
attr.qp_state = IBV_QPS_RTS;
attr.sq_psn = 0;
attr.timeout = 14;
attr.retry_cnt = 7;
attr.rnr_retry = 7;
attr.max_rd_atomic = 1;
ibv_modify_qp(qp, &attr,
IBV_QP_STATE | IBV_QP_SQ_PSN | IBV_QP_TIMEOUT |
IBV_QP_RETRY_CNT | IBV_QP_RNR_RETRY | IBV_QP_MAX_QP_RD_ATOMIC);
/* 5. Receive WR 게시 (수신 측) */
struct ibv_sge recv_sge = { .addr = (uintptr_t)buf,
.length = sizeof(buf), .lkey = mr->lkey };
struct ibv_recv_wr recv_wr = { .sg_list = &recv_sge, .num_sge = 1 };
struct ibv_recv_wr *bad_recv;
ibv_post_recv(qp, &recv_wr, &bad_recv);
/* 6. Send WR 게시 (송신 측) */
memcpy(buf, "Hello RDMA", 10);
struct ibv_sge send_sge = { .addr = (uintptr_t)buf,
.length = 10, .lkey = mr->lkey };
struct ibv_send_wr send_wr = {
.opcode = IBV_WR_SEND,
.send_flags = IBV_SEND_SIGNALED,
.sg_list = &send_sge,
.num_sge = 1,
};
struct ibv_send_wr *bad_send;
ibv_post_send(qp, &send_wr, &bad_send);
/* 7. 완료 폴링 */
struct ibv_wc wc;
while (ibv_poll_cq(cq, 1, &wc) == 0)
; /* busy-wait */
/* 8. 정리 */
ibv_destroy_qp(qp);
ibv_destroy_cq(cq);
ibv_dereg_mr(mr);
ibv_dealloc_pd(pd);
ibv_close_device(ctx);
ibv_free_device_list(dev_list);
return 0;
}
코드 예제 — RDMA Write with librdmacm
/* librdmacm RDMA Write 예제 (클라이언트 측, 간략화) */
#include <rdma/rdma_cma.h>
#include <infiniband/verbs.h>
int main(void)
{
struct rdma_cm_id *id;
struct rdma_event_channel *ec;
struct rdma_conn_param conn_param = {};
struct ibv_pd *pd;
struct ibv_mr *mr;
struct ibv_cq *cq;
char buf[4096];
/* 1. RDMA CM ID 생성 및 주소 해석 */
ec = rdma_create_event_channel();
rdma_create_id(ec, &id, NULL, RDMA_PS_TCP);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(20000),
};
inet_pton(AF_INET, "192.168.1.100", &addr.sin_addr);
rdma_resolve_addr(id, NULL, (struct sockaddr *)&addr, 2000);
/* ... rdma_resolve_route() ... */
/* 2. 리소스 생성 (rdmacm이 QP 상태 전이 자동 처리) */
pd = ibv_alloc_pd(id->verbs);
cq = ibv_create_cq(id->verbs, 16, NULL, NULL, 0);
mr = ibv_reg_mr(pd, buf, sizeof(buf),
IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE);
struct ibv_qp_init_attr qp_attr = {
.send_cq = cq, .recv_cq = cq,
.cap = { .max_send_wr = 16, .max_recv_wr = 16,
.max_send_sge = 1, .max_recv_sge = 1 },
.qp_type = IBV_QPT_RC,
};
rdma_create_qp(id, pd, &qp_attr);
/* 3. 연결 (QP 자동으로 RTS 전이) */
rdma_connect(id, &conn_param);
/* 4. RDMA Write (원격 rkey/addr은 out-of-band로 수신) */
memcpy(buf, "RDMA Write Data", 15);
struct ibv_sge sge = {
.addr = (uintptr_t)buf, .length = 15, .lkey = mr->lkey
};
struct ibv_send_wr wr = {
.opcode = IBV_WR_RDMA_WRITE,
.send_flags = IBV_SEND_SIGNALED,
.sg_list = &sge,
.num_sge = 1,
.wr.rdma = { .remote_addr = remote_addr, .rkey = remote_rkey },
};
struct ibv_send_wr *bad;
ibv_post_send(id->qp, &wr, &bad);
/* 5. 완료 대기 및 정리 */
struct ibv_wc wc;
while (ibv_poll_cq(cq, 1, &wc) == 0);
rdma_disconnect(id);
rdma_destroy_qp(id);
ibv_dereg_mr(mr);
ibv_destroy_cq(cq);
ibv_dealloc_pd(pd);
rdma_destroy_id(id);
rdma_destroy_event_channel(ec);
return 0;
}
sysfs / 디바이스 노드 / ABI
성능 분석이나 장애 대응을 할 때는 Verbs 호출만 보지 말고, 커널이 노출하는 관측 경로를 함께 붙잡아야 합니다.
Linux RDMA 스택은 사용자 API뿐 아니라 /sys/class/infiniband*, /dev/infiniband/*를 통해
상태, 포트 속성, 카운터, ABI 매핑, 관리 디바이스 정보를 꽤 풍부하게 노출합니다.
| 경로 | 의미 | 언제 보는가 |
|---|---|---|
/sys/class/infiniband/<dev>/node_type/sys/class/infiniband/<dev>/node_guid/sys/class/infiniband/<dev>/fw_ver |
장치 종류, GUID, 펌웨어 버전 | 벤더 이슈 분리, 펌웨어 호환성 점검 |
/sys/class/infiniband/<dev>/ports/<port>/{state,phys_state,link_layer,lid,rate,sm_lid,sm_sl} |
포트 활성 상태, 링크 계층, LID, 속도, 연결된 SM 정보 | 포트가 왜 INIT/ACTIVE에 머무는지, InfiniBand와 RoCE를 구분할 때 |
/sys/class/infiniband/<dev>/ports/<port>/counters/* |
링크/패킷/에러 카운터 | 재시도, 링크 에러, 혼잡 징후 확인 |
/sys/class/infiniband/<dev>/ports/<port>/gid_attrs/types/*/sys/class/infiniband/<dev>/ports/<port>/gid_attrs/ndevs/* |
GID 타입과 연동 netdev 매핑 | RoCE GID 해석, IPoIB / Ethernet 연동 확인 |
/sys/class/infiniband_mad/umadN/{ibdev,port} |
umad 문자 디바이스가 어느 HCA/포트와 연결되는지 표시 | opensm, saquery, ibdiagnet가 어떤 포트를 쓰는지 추적 |
/sys/class/infiniband_verbs/uverbsN/{ibdev,abi_version} |
uverbs 장치와 커널 ABI 버전 매핑 | 사용자 공간/커널 ABI mismatch 의심 시 |
# 기본 장치/포트 상태 관찰
cat /sys/class/infiniband/mlx5_0/node_guid
cat /sys/class/infiniband/mlx5_0/fw_ver
cat /sys/class/infiniband/mlx5_0/ports/1/link_layer
cat /sys/class/infiniband/mlx5_0/ports/1/state
cat /sys/class/infiniband/mlx5_0/ports/1/rate
# uverbs / umad가 어느 장치에 매핑되는지 확인
cat /sys/class/infiniband_verbs/uverbs0/ibdev
cat /sys/class/infiniband_mad/umad0/ibdev
cat /sys/class/infiniband_mad/umad0/port
IPoIB (IP over InfiniBand)
IPoIB는 InfiniBand 패브릭 위에서 기존 IP/TCP/UDP 프로토콜을 투명하게 사용할 수 있게 합니다.
커널의 drivers/infiniband/ulp/ipoib/에 구현되어 있으며, ib0, ib1 등의 네트워크 인터페이스로 나타납니다.
Connected Mode vs Datagram Mode
- Datagram Mode (기본): UD QP를 사용합니다. MTU는 IB MTU (보통 2044 바이트, IB 헤더 포함)로 제한됩니다. 브로드캐스트/멀티캐스트를 지원합니다.
- Connected Mode: RC QP를 사용하여 더 큰 MTU(최대 65520 바이트)를 지원합니다. 대용량 IP 트래픽에 적합하지만, 각 peer마다 RC QP가 필요하므로 리소스 소비가 큽니다.
MTU 설정 및 커널 구성
# IPoIB Connected Mode 활성화
echo connected > /sys/class/net/ib0/mode
# Connected Mode MTU 설정 (최대 65520)
ip link set ib0 mtu 65520
# IPoIB 인터페이스에 IP 주소 할당
ip addr add 10.0.0.1/24 dev ib0
ip link set ib0 up
# 커널 구성 옵션
CONFIG_INFINIBAND_IPOIB=m
CONFIG_INFINIBAND_IPOIB_CM=y # Connected Mode 지원
CONFIG_INFINIBAND_IPOIB_DEBUG=y # 디버그 메시지 (선택)
cat /sys/class/net/ib0/mode로 직접 확인하는 편이 가장 확실합니다.
파티션, child interface, Enhanced IPoIB
IPoIB 인터페이스는 기본적으로 포트의 P_Key index 0을 사용합니다. 같은 물리 포트라도 다른 파티션에 참여해야 한다면 P_Key별 child interface를 만들어 별도의 IP 인터페이스처럼 운용할 수 있습니다.
# P_Key 0x8001 파티션용 child interface 생성
echo 0x8001 > /sys/class/net/ib0/create_child
# 생성된 인터페이스 확인 및 활성화
ip link show ib0.8001
ip link set ib0.8001 up
cat /sys/class/net/ib0.8001/pkey
# child interface 삭제
echo 0x8001 > /sys/class/net/ib0/delete_child
상위 프로토콜 (ULP)
| ULP | 프로토콜 계층 | 용도 | 커널 모듈 | 특징 |
|---|---|---|---|---|
| SRP | SCSI over RDMA | 블록 스토리지 | ib_srp / ib_srpt |
SCSI 명령 + 데이터를 RDMA로 전송, iSCSI 대비 저지연 |
| iSER | iSCSI Extensions for RDMA | 블록 스토리지 | ib_iser / ib_isert |
기존 iSCSI 프로토콜을 RDMA로 가속, iSCSI 호환 |
| NVMe-oF/RDMA | NVMe over Fabrics | NVMe 스토리지 | nvme-rdma / nvmet-rdma |
NVMe 큐 모델을 RDMA에 직접 매핑, 초저지연 스토리지 |
| NFS/RDMA | NFS over RDMA (RPCRDMA) | 파일 시스템 | xprtrdma / svcrdma |
RPC 데이터를 RDMA Write/Read로 전송 |
NVMe-oF/RDMA 설정 예제
### NVMe-oF/RDMA Target 설정 ###
# 커널 모듈 로드
modprobe nvmet
modprobe nvmet-rdma
# NVMe-oF 서브시스템 생성
mkdir -p /sys/kernel/config/nvmet/subsystems/nqn.2024-01.io.example:nvme-rdma
cd /sys/kernel/config/nvmet/subsystems/nqn.2024-01.io.example:nvme-rdma
echo 1 > attr_allow_any_host
# 네임스페이스에 NVMe 디바이스 연결
mkdir namespaces/1
echo /dev/nvme0n1 > namespaces/1/device_path
echo 1 > namespaces/1/enable
# RDMA 포트 생성 및 서브시스템 바인드
mkdir -p /sys/kernel/config/nvmet/ports/1
echo rdma > /sys/kernel/config/nvmet/ports/1/addr_trtype
echo 10.0.0.1 > /sys/kernel/config/nvmet/ports/1/addr_traddr
echo 4420 > /sys/kernel/config/nvmet/ports/1/addr_trsvcid
echo ipv4 > /sys/kernel/config/nvmet/ports/1/addr_adrfam
ln -s /sys/kernel/config/nvmet/subsystems/nqn.2024-01.io.example:nvme-rdma \
/sys/kernel/config/nvmet/ports/1/subsystems/
### NVMe-oF/RDMA Initiator (클라이언트) 설정 ###
# 커널 모듈 로드
modprobe nvme-rdma
# Target 디스커버리
nvme discover -t rdma -a 10.0.0.1 -s 4420
# Target 연결
nvme connect -t rdma -n nqn.2024-01.io.example:nvme-rdma \
-a 10.0.0.1 -s 4420
# 연결된 NVMe 디바이스 확인
nvme list
lsblk
관리 및 진단 도구
opensm (Subnet Manager)
opensm은 Linux에서 가장 많이 사용되는 오픈소스 Subnet Manager입니다.
서브넷 토폴로지를 탐색하고 LID를 할당하며, 라우팅 테이블을 계산하여 스위치에 배포합니다.
실제로는 SA 기능도 함께 제공하므로, Path Record 질의와 파티션 정책 배포까지 운영의 중심에 놓입니다.
# opensm 시작 (기본 설정)
opensm
# 포그라운드 + 디버그 레벨 지정
opensm -F -D 0x02
# 특정 포트 GUID로 SM 바인딩
opensm -g 0x0002c90300000001
# 라우팅 알고리즘 지정 (minhop, updn, ftree, dor 등)
opensm --routing_engine ftree
LinkUp인데도 State: Init에 머무르면, 케이블 문제보다 먼저
SM 부재, SM 충돌, 잘못된 GUID 바인딩, IsSM capability bit 충돌을 의심하는 편이 빠릅니다.
진단 도구
# HCA 상태 확인
ibstat
## 출력 예시:
## CA 'mlx5_0'
## CA type: MT4123
## Number of ports: 1
## Port 1:
## State: Active
## Physical state: LinkUp
## Rate: 100 (EDR)
## Base lid: 1
## SM lid: 1
# 디바이스 상세 정보
ibv_devinfo
# 디바이스 속성 (최대 QP 수, MR 크기 등)
ibv_devinfo -v
# SM / SA 상태
sminfo
saquery -s
# 파티션 / 멀티캐스트 / 경로 조회
saquery -p
saquery -m
# 서브넷 노드 목록
ibnetdiscover
# 링크 상태와 포트 정보 요약
iblinkinfo
# 스위치 라우팅 및 경로 추적
ibroute <switch_lid>
# 특정 노드 경로 추적
ibtracert <src_lid> <dst_lid>
# 포트 카운터 확인
perfquery
# fabric 전반 오류 요약
ibqueryerrors
# 포트 에러 카운터 초기화
perfquery -x -r <lid> <port>
# fabric 감사: 토폴로지/라우팅/카운터/케이블 검증
ibdiagnet
# 핑 (GRH 없이 LID 기반)
ibping -S # 서버 모드
ibping <lid> # 클라이언트
ibdiagnet는 단순 카운터 조회를 넘어, 토폴로지 검증, 라우팅 검증, 케이블/BER 확인, 혼잡 제어 설정 점검까지 수행하는
fabric audit 도구입니다. 대규모 클러스터에서는 ibnetdiscover보다 먼저 실행되는 경우도 많습니다.
성능 도구
# RDMA Write 대역폭 측정
ib_write_bw -d mlx5_0 # 서버
ib_write_bw -d mlx5_0 <server_ip> # 클라이언트
# RDMA Write 지연시간 측정
ib_write_lat -d mlx5_0 # 서버
ib_write_lat -d mlx5_0 <server_ip> # 클라이언트
# Send/Recv 대역폭/지연
ib_send_bw, ib_send_lat
# RDMA Read 대역폭/지연
ib_read_bw, ib_read_lat
# Atomic 연산 지연
ib_atomic_lat -d mlx5_0 <server_ip>
rdma (iproute2 rdma tool)
# RDMA 디바이스 목록
rdma dev
# RDMA 링크 상태
rdma link
# RDMA 통계 (상세)
rdma statistic show
# RDMA 리소스 (QP, CQ, MR 등) 목록
rdma resource show
# 특정 디바이스의 QP 목록
rdma resource show qp -d mlx5_0
# 포트별 GID / 링크 계층 / netdev 매핑 확인
rdma link show mlx5_0/1
# netns에서 RDMA 디바이스 사용 설정
rdma system set netns shared
성능 최적화
Adaptive Routing / SR-IOV
- Adaptive Routing (AR): HDR 이상의 IB 스위치가 실시간 네트워크 혼잡도를 감지하여 패킷 경로를 동적으로 변경합니다. 특히 All-to-All 통신 패턴(AI/ML 학습)에서 효과적입니다.
- 다중 레일(Multi-Rail): 노드당 2개 이상 HCA/포트를 두고 MPI/스토리지 트래픽을 레일별로 분산하면 단일 링크 병목과 장애 범위를 줄일 수 있습니다.
- SL/VL 기반 QoS: 대역폭만 늘리는 것보다, 지연 민감 제어 트래픽과 대용량 데이터 트래픽을 서로 다른 SL/VL 정책으로 분리하는 것이 더 큰 효과를 낼 때가 많습니다.
- SR-IOV: 하나의 물리 HCA를 여러 Virtual Function(VF)으로 분할하여 각 VM/컨테이너에 독립적인 RDMA 디바이스를 제공합니다. PCI/PCIe 서브시스템과 가상화 (KVM) 페이지도 참고하세요.
메모리 핀닝/등록 최적화
- 대용량 페이지(Huge Pages): 2MB/1GB 페이지를 사용하면 MR 등록 시 페이지 테이블 워크가 줄어들고, TLB 미스도 감소합니다.
- ODP (On-Demand Paging): 메모리를 미리 핀하지 않고 HCA 페이지 폴트 시 동적으로 매핑합니다. 등록 시간은 단축되지만 첫 접근 시 오버헤드가 있습니다.
- MR 풀링: 자주 사용하는 MR을 미리 등록하고 재사용합니다.
ib_mr_pool커널 API 또는 사용자 공간에서 직접 구현합니다. - NUMA 배치: HCA와 같은 NUMA 노드의 메모리를 사용하면 DMA 전송 성능이 향상됩니다. 메모리 심화 및 NUMA 페이지를 참고하세요.
Completion Channel vs Polling
- Polling (ibv_poll_cq): CQ를 busy-wait으로 폴링합니다. 최저 지연이 필요할 때 사용하지만, CPU 코어를 100% 점유합니다.
- Completion Channel:
ibv_get_cq_event()로 이벤트를 대기합니다. CPU를 절약하지만 이벤트 전달 지연이 추가됩니다. - 하이브리드: 평소에는 polling으로 처리하다가 유휴 시 completion channel로 전환하는 적응형 방식이 실무에서 많이 사용됩니다.
QP / CQ 튜닝
- 깊이 설계: QP depth와 CQE 수가 너무 작으면
RNR, CQ overrun, 재시도 증가로 이어집니다. 반대로 과도하면 캐시와 메모리 압력이 커집니다. - Unsignaled Completion: 모든 WR에 completion을 요구하면 CQ 트래픽이 폭증합니다. 벌크 전송은 주기적으로만 signaled WR을 넣는 방식이 일반적입니다.
- 배치 posting: 작은 WR을 여러 개 묶어 post하면 doorbell/MMIO 비용을 줄일 수 있습니다. 대규모 RPC보다 스트리밍 전송에서 특히 중요합니다.
- Completion vector / IRQ affinity: CQ와 poller 스레드를 HCA와 같은 NUMA 노드에 배치하고 인터럽트 affinity를 맞추면 tail latency가 크게 줄어듭니다.
- CQE compression / moderation: provider가 지원하면 CQE 압축과 moderation으로 PCIe 및 CPU 부담을 줄일 수 있지만, 초저지연 단건 RPC에는 오히려 손해일 수 있습니다.
GPUDirect RDMA
NVIDIA GPUDirect RDMA는 GPU 메모리를 RDMA MR로 직접 등록하여, CPU 메모리를 거치지 않고 GPU ↔ HCA 간 직접 P2P DMA 전송을 수행합니다. AI/ML 분산 학습에서 GPU 간 gradient 교환 성능을 극적으로 향상시킵니다.
- 전통 경로: peer-memory 드라이버가 GPU 페이지를 핀하고 HCA가 이를 MR처럼 접근합니다.
- 현대 경로: 사용자 공간에서 dma-buf 기반 MR 등록을 사용해 GPU/가속기 메모리를 직접 연결하는 방식이 점점 중요해지고 있습니다.
- 검증 도구:
perftest는--use_cuda,--use_cuda_dmabuf같은 옵션으로 GPU 메모리 경로를 직접 검증할 수 있습니다. - 주의점: 동일 PCIe root complex, IOMMU 설정, peer-memory 모듈, CUDA/OFED/rdma-core 버전 호환성이 모두 맞아야 합니다.
DMA 심화 페이지의 P2P DMA / GPUDirect 섹션도 참고하세요.
ulimit -l로 프로세스별 메모리 잠금 제한을 확인하고, /etc/security/limits.conf에서
RDMA 사용자의 memlock 값을 적절히 설정해야 합니다.
컨테이너 환경에서는 cgroups의 memory.max도 함께 고려해야 합니다.
격리와 멀티테넌시
InfiniBand는 본질적으로 강한 성능 지향 기술이지만, 클라우드·공유 HPC·AI 플랫폼에서는 누가 어느 HCA 자원을 얼마나 쓰는지, 어느 파티션까지 접근 가능한지를 함께 설계해야 합니다. 단순히 디바이스 파일 권한만 나눠 주는 것으로는 충분하지 않습니다.
패브릭 격리: P_Key, SL, SR-IOV
- P_Key: 패브릭 수준 논리 분할입니다. IPoIB child interface, RC/UD 통신, 멀티캐스트 구성 모두 P_Key membership의 영향을 받습니다.
- SL / QoS 정책: 테넌트별 또는 워크로드별 우선순위 분리를 구현할 때 쓰입니다. 대역폭 제어가 아니라 지연 격리에 더 가깝습니다.
- SR-IOV VF: VM/컨테이너에 VF를 직접 넘기면 성능은 좋지만, 펌웨어/하이퍼바이저/게스트 드라이버 조합이 모두 맞아야 하며 PF 수준 기능 일부는 노출되지 않을 수 있습니다.
RDMA cgroup controller
현재 커널 문서는 RDMA controller가 프로세스 집합별로 RDMA/IB 자원 사용량을 제한한다고 설명합니다.
인터페이스는 rdma.max, rdma.current 파일을 통해 노출되며, 장치별로 hca_handle, hca_object 한도를 설정합니다.
| 제어 항목 | 의미 | 실무 해석 |
|---|---|---|
hca_handle |
RDMA 장치 핸들 수 제한 | 프로세스군이 열 수 있는 HCA 컨텍스트 수를 제한합니다. |
hca_object |
RDMA 객체 수 제한 | QP, CQ, MR, AH 등 하드웨어/커널 객체 총량을 묶어서 제어합니다. |
# cgroup v2 예시: mlx5_0의 RDMA 자원 제한
mkdir -p /sys/fs/cgroup/tenant-a
echo '+rdma' > /sys/fs/cgroup/cgroup.subtree_control
echo 'mlx5_0 hca_handle=4 hca_object=2000' > /sys/fs/cgroup/tenant-a/rdma.max
# 현재 사용량 확인
cat /sys/fs/cgroup/tenant-a/rdma.current
cat /sys/fs/cgroup/tenant-a/rdma.max
/dev/infiniband/uverbs0만 넘겨도, memlock, cgroup RDMA 제한,
IOMMU 정책, VF/PF 매핑, GPU dma-buf 권한이 맞지 않으면 성능과 안정성이 바로 깨집니다.
RDMA 자원 격리는 반드시 디바이스 파일 + cgroup + 패브릭 파티션을 같이 봐야 합니다.
네임스페이스와 capability 위임
- network namespace: netdev는 네임스페이스에 들어가도 RDMA 디바이스 자체는 별도 관리 경로를 가집니다. 운영 중
rdma system set netns shared같은 정책이 왜 필요한지 여기서 드러납니다. - UCAP (Userspace Capabilities): 최신 커널 문서는 일부 저수준 기능을 더 세분화된 권한 모델로 위임하는 방향을 설명합니다. DevX류 기능을 모두에게 열지 않으려는 흐름입니다.
- 장치 파일 권한:
/dev/infiniband/rdma_cm,uverbs,umad는 성격이 서로 다르므로, 단순히chmod 666로 풀어 버리면 관리 평면까지 과도하게 열릴 수 있습니다.
트러블슈팅 및 주의사항
- InfiniBand: SM/SA, LID, P_Key, SL/VL, credit-based flow control, Path Record를 먼저 확인
- RoCE: PFC, ECN/DCQCN, VLAN/DSCP, lossless 큐, GID/IP 라우팅을 먼저 확인
ibv_devinfo와 rdma link에서 link_layer가 무엇인지부터 보세요.
일반적인 트러블슈팅 순서:
ibstat,ibv_devinfo,rdma link으로 포트 상태와 link_layer를 확인합니다.sminfo,saquery -s,ibnetdiscover로 SM/SA와 fabric discovery가 정상인지 확인합니다.saquery -p,ibroute,ibtracert로 P_Key와 실제 경로를 점검합니다.perfquery,ibqueryerrors,ibdiagnet로 포트 카운터와 fabric 오류를 수집합니다.rdma resource show,dmesg | grep -i rdma로 QP/CQ/MR과 커널 로그를 확인합니다.ib_write_bw,ib_send_bw, 필요하면 GPU 옵션이 붙은 perftest로 재현 가능한 성능 기준선을 만듭니다.
| 증상 | 먼저 볼 것 | 흔한 원인 |
|---|---|---|
| 포트가 INIT에서 올라오지 않음 | ibstat, sminfo, opensm 로그 |
SM 부재, 잘못된 GUID 바인딩, 케이블/모듈 문제, 포트 speed negotiation 실패 |
| QP가 RTR/RTS로 전이되지 않음 | QPN, LID/GID, PSN, MTU, P_Key | out-of-band 교환 값 오류, 경로 해석 실패, 파티션 불일치 |
IB_WC_REM_ACCESS_ERR, REM_INV_REQ_ERR |
MR access flags, rkey, remote_addr | 잘못된 rkey 전달, 원격 버퍼 길이 초과, MW/MR 무효화 이후 접근 |
RNR retry exceeded |
RQ depth, SRQ, 수신 버퍼 게시 타이밍 | 수신 측이 Receive WR을 충분히 post하지 않음, CQ poller 지연 |
| 대역폭이 선형으로 안 나옴 | NUMA 배치, CQE 수, signaled 비율, MTU, multi-rail | HCA와 메모리의 NUMA 불일치, 너무 잦은 completion, 작은 큐 깊이, 혼잡/경로 편중 |
| IPoIB child interface에 트래픽이 없음 | /sys/class/net/*/pkey, SA 파티션 정보 |
파티션 membership 누락, 잘못된 P_Key index, connected/datagram mode 혼선 |
자주 보는 Work Completion 상태
실패한 WR은 결국 CQ의 ibv_wc.status로 드러납니다. rdma-core의 enum ibv_wc_status를 기준으로,
현장에서 가장 자주 보는 상태는 다음 정도입니다.
ibv_wc_status | 의미 | 우선 확인할 것 |
|---|---|---|
IBV_WC_SUCCESS |
정상 완료 | 지연/처리량 문제면 큐 깊이, polling, NUMA, MTU 쪽으로 이동 |
IBV_WC_LOC_LEN_ERR |
로컬 SGE 길이/버퍼 범위 오류 | SGE length, MR 길이, receive buffer 크기 |
IBV_WC_LOC_PROT_ERR |
로컬 보호 오류 | lkey, access flag, 잘못된 MR 재사용 여부 |
IBV_WC_WR_FLUSH_ERR |
QP가 error 상태로 가며 미완료 WR이 flush됨 | 그 전에 발생한 최초 에러, QP 이벤트 핸들러 로그 |
IBV_WC_REM_ACCESS_ERR |
원격 접근 권한 오류 | 원격 MR access flag, rkey, remote_addr 범위 |
IBV_WC_RETRY_EXC_ERR |
재시도 횟수 초과 | 상대 QP 상태, 경로 단절, PSN/MTU 불일치, 혼잡/링크 오류 |
IBV_WC_RNR_RETRY_EXC_ERR |
RNR 재시도 초과 | 수신 측 Receive WR 게시 누락, SRQ 고갈, poller 지연 |
IBV_WC_WR_FLUSH_ERR는 대개 2차 증상입니다. flush가 보이면 그 직전에 발생한
RETRY_EXC, REM_ACCESS, 링크 down 이벤트를 먼저 찾는 편이 훨씬 빠릅니다.
커널 모듈 관련 이슈는 네트워크 스택 페이지를, PCIe/SR-IOV 관련 문제는 PCI/PCIe 서브시스템 페이지를 참고하세요.
프로덕션 배포 체크리스트
InfiniBand는 단일 설정값 하나로 안정화되는 기술이 아닙니다. 하드웨어, 패브릭, 메모리, 애플리케이션이 모두 같은 방향으로 맞아야 하므로 배포 전 체크 순서를 명확히 고정하는 것이 중요합니다.
- PCIe / 펌웨어 정합성
HCA가 기대한 링크 폭/속도로 올라왔는지, 펌웨어와 드라이버 조합이 지원 매트릭스 안에 있는지 확인합니다. - 패브릭 활성화
ibstat가Active,sminfo가 정상, LID와 P_Key가 의도한 값으로 배포됐는지 확인합니다. - 단일 흐름 기준선
ib_write_bw,ib_write_lat,ib_send_bw로 단일 QP/단일 코어 기준선을 먼저 만듭니다. - NUMA / IRQ / poller 배치
HCA와 같은 NUMA 노드에 메모리와 스레드를 묶고 CQ completion vector, IRQ affinity를 정렬합니다. - 애플리케이션 모델 선택
제어 메시지는 Send/Recv, 대용량 데이터는 RDMA Write/Read, 대규모 fan-in은 SRQ/XRC/DC로 분리 설계합니다. - 상위 프로토콜 검증
IPoIB, NFS/RDMA, NVMe-oF/RDMA, GPU 메모리 경로를 각각 별도 기준선으로 확인합니다. 기본 RDMA가 빠르다고 ULP도 자동으로 빠른 것은 아닙니다. - 지속 관측 체계
perfquery,ibqueryerrors,ibdiagnet,rdma statistic show를 정기 수집에 포함합니다. - 장애 시 격리 순서
애플리케이션 → Verbs → QP/CQ/MR → 포트 상태 → SM/SA → 스위치 경로 → PCIe/IOMMU 순으로 아래로 내려가며 원인을 좁힙니다.
2노드 Bring-up 시나리오
새 장비를 랙에 넣었을 때 가장 안전한 방식은, 복잡한 스토리지나 MPI 스택을 바로 올리지 말고 두 노드만 연결한 최소 구성에서 패브릭, Verbs, IPoIB, 성능 기준선을 순서대로 확인하는 것입니다.
- 드라이버와 관리 도구 로드
mlx5_ib,ib_umad, 필요하면ib_ipoib가 올라왔는지 확인합니다. - SM 확보
스위치 내장 SM이 없다면 한 노드에서opensm을 띄우고 다른 노드 포트가INIT → ACTIVE로 전이되는지 봅니다. - 기본 관측
ibstat,ibv_devinfo,sminfo,saquery -s로 포트 상태와 SM/SA를 점검합니다. - Verbs 기준선
ib_write_bw,ib_write_lat,ib_send_bw만으로 HCA-to-HCA 경로를 먼저 검증합니다. - IP 계층 확인
필요하면 IPoIB를 올리고ip addr,ping, 애플리케이션 포트 바인딩을 점검합니다. - 애플리케이션 계층 확장
그 다음에야 UCX/Open MPI, NVMe-oF, NFS/RDMA, GPU direct를 하나씩 붙입니다.
# 노드 A: SM이 필요하면 시작
modprobe mlx5_ib ib_umad
opensm -F
# 양 노드: 포트 상태 확인
ibstat
ibv_devinfo
sminfo
# 양 노드: Verbs 기준선 측정
# 노드 A (server)
ib_write_bw -d mlx5_0
# 노드 B (client)
ib_write_bw -d mlx5_0 <server_name_or_ip>
# 필요 시 IPoIB 확인
modprobe ib_ipoib
ip link set ib0 up
ip addr add 10.10.10.1/24 dev ib0
관련 문서
이 주제와 관련된 다른 문서를 더 깊이 이해하고 싶다면 다음을 참고하세요.