Add GS Mock Mode feasibility analysis

This commit is contained in:
accusys
2026-03-29 14:39:44 +08:00
parent e6357420ec
commit 27da85879f
+520
View File
@@ -0,0 +1,520 @@
# 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: 編譯時開關 (推薦)
```c
// hInclude.h
#ifdef ENABLE_MOCK_MODE
#include "mock_driver.h"
#define DevIoControl mock_DevIoControl
#define QuaryDTR mock_QuaryDTR
#define GetCtlrEvent mock_GetCtlrEvent
#endif
```
### 方案 2: 執行時開關
```c
// runtime_config.h
extern BOOL g_bMockMode;
// 初始化時檢查
if (g_bMockMode) {
initMockDriver();
} else {
initRealDriver();
}
```
### 方案 3: 環境變數
```bash
# 啟動時設定
export DTR_GUI_MOCK_MODE=1
./DtrGuiSrv01
```
## 需要實現的 Mock 函數
### 1. mock_driver.h
```c
#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
```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
```c
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 |
## 模擬事件
### 預設模擬事件
```c
// 初始化時註冊一些模擬事件
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
```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
```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
```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. 環境變數
```bash
# 啟用 Mock 模式
export DTR_GUI_MOCK_MODE=1
./DtrGuiSrv01
# 指定 Mock 設定檔
export DTR_GUI_MOCK_CONFIG=./mock_config.json
./DtrGuiSrv01
```
### 2. 命令列參數
```bash
./DtrGuiSrv01 --mock
./DtrGuiSrv01 -m
./DtrGuiSrv01 --mock-config ./mock_config.json
```
### 3. 設定檔
```ini
# dtr_guiconf.ini
[Server]
Port=8922
MockMode=1
MockConfig=./mock_config.json
```
## 測試案例
### 1. 基本連線測試
```python
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. 控制器查詢測試
```python
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. 事件測試
```python
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 標記
```c
// 回應中加入 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` - 模擬設定檔範例
- 編譯腳本更新