Files
rust_raidguardx/GS_MockMode_Analysis.md
T
2026-03-29 14:39:44 +08:00

13 KiB

GS Mock Mode 模擬模式分析

概述

為 GS (DtrGuiSrv) 新增 Mock 模擬模式,無需 RAID Driver 即可運行,用於:

  • 開發測試
  • CI/CD 自動化測試
  • 離線 Demo
  • 功能驗證

需要模擬的關鍵函數

1. Driver I/O 層

函數 用途 模擬難度
DevIoControl() I/O Control 與 Driver 通訊
QuaryDTR() 查詢 RAID 控制器資訊
GetCtlrEvent() 取得控制器事件

2. 共享記憶體層

函數 用途 模擬難度
InitialSHMForAllCtlr() 初始化共享記憶體
相關 SHM 函數 共享記憶體操作

模擬模式架構

┌─────────────────────────────────────────────────────────────────────┐
│                    GS Mock Mode 架構                                │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐  │
│  │                    GS (DtrGuiSrv)                           │  │
│  │                                                              │  │
│  │  ┌─────────────────────────────────────────────────────┐   │  │
│  │  │              Mock Mode 開關                           │   │  │
│  │  │  #define ENABLE_MOCK_MODE                           │   │  │
│  │  └─────────────────────────────────────────────────────┘   │  │
│  │                            │                                 │  │
│  │         ┌──────────────────┼──────────────────┐              │  │
│  │         ▼                  ▼                  ▼              │  │
│  │  ┌─────────────┐   ┌─────────────┐   ┌─────────────┐   │  │
│  │  │ Real Driver │   │ Mock Driver │   │ Mock Data   │   │  │
│  │  │  (Production)│   │  (Dev/Mock)  │   │  (Static)   │   │  │
│  │  └─────────────┘   └─────────────┘   └─────────────┘   │  │
│  └─────────────────────────────────────────────────────────────┘  │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

實現方案

方案 1: 編譯時開關 (推薦)

// hInclude.h
#ifdef ENABLE_MOCK_MODE
    #include "mock_driver.h"
    #define DevIoControl mock_DevIoControl
    #define QuaryDTR mock_QuaryDTR
    #define GetCtlrEvent mock_GetCtlrEvent
#endif

方案 2: 執行時開關

// runtime_config.h
extern BOOL g_bMockMode;

// 初始化時檢查
if (g_bMockMode) {
    initMockDriver();
} else {
    initRealDriver();
}

方案 3: 環境變數

# 啟動時設定
export DTR_GUI_MOCK_MODE=1
./DtrGuiSrv01

需要實現的 Mock 函數

1. mock_driver.h

#ifndef MOCK_DRIVER_H
#define MOCK_DRIVER_H

#include "hInclude.h"

// Mock 初始化
void mock_init(void);
void mock_cleanup(void);

// Mock 控制器數據
typedef struct {
    UCHAR bStatus;
    UCHAR bCtlrSN[16];
    UCHAR bModelName[32];
    UCHAR bPage0Data[1024];  // Controller Info Page
    UCHAR bPage1Data[1024];  // RAID Snapshot
    // ...
} MOCK_CTRL_INFO;

// Mock DevIoControl
UCHAR mock_DevIoControl(
    UCHAR bDevNo,
    ULONG lControlCode,
    ULONG lInSize,
    PCHAR pInBuf,
    ULONG lOutSize,
    PCHAR pOutBuf,
    USHORT *pusInBandErrCode
);

// Mock QuaryDTR
CHAR mock_QuaryDTR(
    UCHAR ucCtlrIndex,
    UCHAR *bPageBuf,
    UCHAR *pbHeatsink
);

// Mock GetCtlrEvent
UCHAR mock_GetCtlrEvent(
    UCHAR bCtlrNo,
    PEVENT_INFO pEvent_info
);

// 設定模擬事件
void mock_set_event(UCHAR *eventData, int length);
void mock_clear_events(void);

// 控制器狀態控制
void mock_set_controller_online(BOOL online);
void mock_set_controller_count(int count);

#endif

2. mock_driver.c

#include "mock_driver.h"

// 單例 Mock 控制器資訊
static MOCK_CTRL_INFO g_mockCtrl[MAX_DTR_IN_HOST];
static BOOL g_bMockInitialized = FALSE;

// 模擬的事件佇列
static UCHAR g_mockEventQueue[100][512];
static int g_mockEventCount = 0;

void mock_init(void) {
    if (g_bMockInitialized) return;
    
    // 初始化 Mock 控制器
    memset(g_mockCtrl, 0, sizeof(g_mockCtrl));
    
    // 預設控制器 1 台,狀態上線
    g_mockCtrl[0].bStatus = CTLR_STATUS_ALIVE;
    memcpy(g_mockCtrl[0].bCtlrSN, "MOCK00000001", 16);
    memcpy(g_mockCtrl[0].bModelName, "Accusys Mock RAID", 32);
    
    // 填充 Page 0 資料 (Controller Info)
    fill_mock_page0(g_mockCtrl[0].bPage0Data);
    
    g_bMockInitialized = TRUE;
    
    printf("[MOCK] Driver initialized\n");
}

UCHAR mock_DevIoControl(...) {
    if (!g_bMockInitialized) mock_init();
    
    // 根據 Control Code 處理
    switch (lControlCode) {
        case IOCTL_DTR_GET_CONTROLLER_INFO:
            // 回傳控制器資訊
            break;
            
        case IOCTL_DTR_GET_INBAND_EVENT:
            // 回傳模擬事件
            break;
            
        case IOCTL_DTR_SET_INBAND_COMMAND:
            // 處理命令,回傳成功
            break;
            
        default:
            // 預設回傳成功
            *pusInBandErrCode = 0;
            return SYSOK;
    }
    
    return SYSOK;
}

CHAR mock_QuaryDTR(UCHAR ucCtlrIndex, UCHAR *bPageBuf, UCHAR *pbHeatsink) {
    if (!g_bMockInitialized) mock_init();
    
    if (ucCtlrIndex >= MAX_DTR_IN_HOST) {
        return FALSE;
    }
    
    // 複製 Mock 資料
    memcpy(bPageBuf, g_mockCtrl[ucCtlrIndex].bPage0Data, 1024);
    *pbHeatsink = 0x00;
    
    return TRUE;
}

UCHAR mock_GetCtlrEvent(UCHAR bCtlrNo, PEVENT_INFO pEvent_info) {
    if (!g_bMockInitialized) mock_init();
    
    // 從佇列取出事件
    if (g_mockEventCount > 0) {
        memcpy(pEvent_info->bEventBuf, g_mockEventQueue[0], 512);
        pEvent_info->bStatus = TRUE;
        
        // 移除已取出的事件
        g_mockEventCount--;
        // ... 佇列搬移
        
        return SYSOK;
    }
    
    pEvent_info->bStatus = FALSE;
    return SYSFAIL_EVENT_EMPTY;
}

模擬的 Page 資料

Page 0: Controller Info

void fill_mock_page0(UCHAR *buf) {
    // Offset 0-31: Serial Number
    memcpy(buf + 0, "MOCK00000001", 16);
    
    // Offset 32-63: Model Name
    memcpy(buf + 32, "Accusys Mock RAID", 20);
    
    // Offset 64-95: Firmware Version
    memcpy(buf + 64, "1.0.0.0", 8);
    
    // 其他欄位...
    // 需要完整對應 Java GUI 解析的格式
}

需要的 Page

Page 大小 用途
0x00 1024 Controller Info
0x01 1024 RAID Snapshot
0x07 512 LUN Map Table
0x0A-0x0E 1024 RAID Info
0x10-0x11 512 Disk/Slice Names
0x14 512 Array Info
0x1A 512 Enclosure Info
0x1B 512 Disk List

模擬事件

預設模擬事件

// 初始化時註冊一些模擬事件
void mock_register_default_events(void) {
    // 磁碟上線事件
    UCHAR diskOnlineEvent[] = {
        0x01, 0x00, 0x00, 0x00,  // Event Type
        0x00, 0x00, 0x00, 0x00,  // Timestamp
        0x01, 0x02, 0x00, 0x00,  // Slot 1, Online
        // ...
    };
    mock_set_event(diskOnlineEvent, 32);
    
    // RAID 重建完成事件
    UCHAR rebuildDoneEvent[] = {
        0x02, 0x00, 0x00, 0x00,  // Event Type
        // ...
    };
    mock_set_event(rebuildDoneEvent, 32);
}

配置檔案

mock_config.json

{
    "mock_mode": true,
    "controller_count": 2,
    "controllers": [
        {
            "serial_number": "MOCK00000001",
            "model_name": "Accusys GEN2",
            "firmware_version": "3.8.0",
            "status": "online",
            "raid_arrays": [
                {
                    "id": 0,
                    "level": "RAID5",
                    "disks": [0, 1, 2, 3],
                    "status": "Normal",
                    "capacity": 10000000
                }
            ],
            "disks": [
                {"slot": 0, "status": "Online", "capacity": 4000000},
                {"slot": 1, "status": "Online", "capacity": 4000000},
                {"slot": 2, "status": "Online", "capacity": 4000000},
                {"slot": 3, "status": "Online", "capacity": 4000000},
                {"slot": 4, "status": "Online", "capacity": 4000000, "spare": true}
            ]
        },
        {
            "serial_number": "MOCK00000002",
            "model_name": "Accusys GEN2",
            "status": "online"
        }
    ],
    "events": [
        {
            "type": "DiskOnline",
            "slot": 2,
            "timestamp": 1234567890
        }
    ]
}

編譯選項

Makefile

# 一般編譯
build:
	gcc -o DtrGuiSrv01 *.c -lpthread -lm

# Mock 模式編譯
build-mock:
	gcc -o DtrGuiSrv01_mock *.c -DENABLE_MOCK_MODE -lpthread -lm

# 兩者區別
ifdef ENABLE_MOCK_MODE
	CFLAGS += -DENABLE_MOCK_MODE
	SRCS += mock_driver.c
endif

CMake

option(ENABLE_MOCK "Enable mock mode for testing" OFF)

if(ENABLE_MOCK)
    add_definitions(-DENABLE_MOCK_MODE)
    set(MOCK_SOURCES mock_driver.c)
endif()

add_executable(DtrGuiSrv01 ${SOURCES} ${MOCK_SOURCES})

執行模式

1. 環境變數

# 啟用 Mock 模式
export DTR_GUI_MOCK_MODE=1
./DtrGuiSrv01

# 指定 Mock 設定檔
export DTR_GUI_MOCK_CONFIG=./mock_config.json
./DtrGuiSrv01

2. 命令列參數

./DtrGuiSrv01 --mock
./DtrGuiSrv01 -m
./DtrGuiSrv01 --mock-config ./mock_config.json

3. 設定檔

# dtr_guiconf.ini
[Server]
Port=8922
MockMode=1
MockConfig=./mock_config.json

測試案例

1. 基本連線測試

import socket

def test_connection():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('localhost', 8922))
    
    # 發送 GET_PAGE 請求
    request = build_get_page_request(page_code=0x00)
    s.send(request)
    
    # 驗證回應
    response = s.recv(4096)
    assert response[0] == 0x50  # Success
    
    s.close()

2. 控制器查詢測試

def test_query_controller():
    # 查詢控制器資訊
    response = send_inband_command(opcode=0x01, page=0x00)
    
    # 驗證資料格式
    assert response['serial_number'] == 'MOCK00000001'
    assert response['model_name'] == 'Accusys Mock RAID'

3. 事件測試

def test_event_polling():
    # 設定模擬事件
    mock_set_event(disk_online_event)
    
    # 取得事件
    response = send_event_request(opcode=0x02)
    
    # 驗證事件
    assert response['event_type'] == 'DiskOnline'

實作時間評估

工作項目 時間
建立 mock_driver.h/c 框架 1 天
實作基本 DevIoControl 2 天
實作 QuaryDTR / GetCtlrEvent 1 天
實作 Page 0 (Controller Info) 1 天
實作其他 Page 資料 2-3 天
模擬事件系統 1 天
JSON 設定檔支援 1 天
測試與除錯 2 天
總計 9-10 天

風險與限制

已知限制

  1. 不完整模擬: 無法完全模擬所有 RAID 操作
  2. 狀態有限: 只能模擬基本狀態
  3. Driver 特定: 某些低層級錯誤無法模擬

風險控制

  1. 清晰標記: Mock 模式下顯示明顯標識
  2. 日誌區分: Mock 日誌使用不同前綴 [MOCK]
  3. 版本標記: 回應中包含 Mock 標記
// 回應中加入 Mock 標記
UCHAR mock_page0[] = {
    // ...
    'M', 'O', 'C', 'K',  // 識別碼
    // ...
};

結論

可行性:

結論: 完全可行,預估 9-10 天可完成。

實作策略

  1. 先實現基本框架: 快速建立可運行的 Mock 骨架
  2. 逐步完善: 按需求添加更多 Page 支援
  3. 測試驅動: 先寫測試案例,再實作對應 Mock

優點

  • 開發期不需要實際 RAID 硬體
  • CI/CD 可自動化測試
  • 容易重現問題
  • 教學演示方便

產出

  • mock_driver.h - Mock 驅動介面
  • mock_driver.c - Mock 驅動實作
  • mock_config.json - 模擬設定檔範例
  • 編譯腳本更新