-
Notifications
You must be signed in to change notification settings - Fork 126
feat(starry): report EOPNOTSUPP for SIOCETHTOOL and expose /proc/pid/mountinfo #1508
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
test-suit/starryos/qemu-smp1/system/syscall-test-ethtool-ioctl/CMakeLists.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| cmake_minimum_required(VERSION 3.20) | ||
| project(test-ethtool-ioctl C) | ||
| set(CMAKE_C_STANDARD 11) | ||
| set(CMAKE_C_STANDARD_REQUIRED ON) | ||
| set(CMAKE_C_EXTENSIONS OFF) | ||
| add_executable(test-ethtool-ioctl src/main.c) | ||
| target_include_directories(test-ethtool-ioctl PRIVATE src) | ||
| target_compile_options(test-ethtool-ioctl PRIVATE -Wall -Wextra -Werror) | ||
| install(TARGETS test-ethtool-ioctl RUNTIME DESTINATION usr/bin/starry-test-suit) |
121 changes: 121 additions & 0 deletions
121
test-suit/starryos/qemu-smp1/system/syscall-test-ethtool-ioctl/src/main.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| #define _GNU_SOURCE | ||
| #include "test_framework.h" | ||
| #include <net/if.h> | ||
| #include <sys/ioctl.h> | ||
| #include <sys/socket.h> | ||
| #include <unistd.h> | ||
|
|
||
| /* | ||
| * SIOCETHTOOL ioctl 回归测试。 | ||
| * | ||
| * 触发背景 (为什么写这个测例): | ||
| * glances 的 NETWORK 区块通过 psutil 的 net_if_stats() 采集每个接口的状态, | ||
| * 其中 speed/duplex 用 SIOCETHTOOL (ETHTOOL_GSET) 查询 PHY 链路。starry 没有 | ||
| * 模拟 PHY, 此前 SIOCETHTOOL 落到 socket ioctl 的默认分支返回 ENOTTY。psutil | ||
| * 只把 EOPNOTSUPP 当作"无 ethtool"优雅降级, 遇到任何其它 errno 会 abort 整个 | ||
| * interface-status 探测 -> glances NETWORK 区块渲染崩溃。内核现在像虚拟网卡 | ||
| * (loopback / tun/tap) 一样对 SIOCETHTOOL 返回 EOPNOTSUPP。 | ||
| * | ||
| * Linux 参照 (fresh host, kernel 6.6): | ||
| * ioctl(AF_INET sock, SIOCETHTOOL, {ifr_name="lo"}) => -1 errno=EOPNOTSUPP(95); | ||
| * loopback 无 ethtool_ops, dev_ethtool() 返回 -EOPNOTSUPP。 | ||
| * | ||
| * 断言: | ||
| * 1. AF_INET SOCK_DGRAM 套接字创建成功。 | ||
| * 2. 对 "lo" 发 SIOCETHTOOL 返回 -1 (查询被拒)。 | ||
| * 3. errno == EOPNOTSUPP (优雅"无 ethtool"; 修复前是 ENOTTY, 会让 psutil abort)。 | ||
| */ | ||
|
|
||
| /* linux-raw-sys / <linux/sockios.h> 常量, arch 无关; 避免依赖 <linux/ethtool.h>。*/ | ||
| #ifndef SIOCETHTOOL | ||
| #define SIOCETHTOOL 0x8946 | ||
| #endif | ||
| #define ETHTOOL_GSET 0x00000001u | ||
|
|
||
| int main(void) | ||
| { | ||
| TEST_START("SIOCETHTOOL returns EOPNOTSUPP on virtual NIC"); | ||
| char msg[160]; | ||
|
|
||
| int fd = socket(AF_INET, SOCK_DGRAM, 0); | ||
| CHECK(fd >= 0, "socket(AF_INET, SOCK_DGRAM) 创建成功"); | ||
| if (fd < 0) { | ||
| TEST_DONE(3); | ||
| } | ||
|
|
||
| /* | ||
| * ifr_data 指向一个 ethtool 命令字 (ETHTOOL_GSET)。内核在读取 ifr_data 之前 | ||
| * 就返回 EOPNOTSUPP, 但仍按 psutil 的真实调用形态填好请求。 | ||
| */ | ||
| unsigned int ethcmd = ETHTOOL_GSET; | ||
| struct ifreq ifr; | ||
| memset(&ifr, 0, sizeof ifr); | ||
| strncpy(ifr.ifr_name, "lo", IFNAMSIZ - 1); | ||
| ifr.ifr_data = (void *)ðcmd; | ||
|
|
||
| errno = 0; | ||
| int ret = ioctl(fd, SIOCETHTOOL, &ifr); | ||
| int saved_errno = errno; | ||
| close(fd); | ||
|
|
||
| snprintf(msg, sizeof msg, "SIOCETHTOOL 查询被拒 ret == -1 (实际 %d)", ret); | ||
| CHECK(ret == -1, msg); | ||
|
|
||
| snprintf(msg, sizeof msg, | ||
| "errno == EOPNOTSUPP(%d) 优雅降级 (实际 %d %s; 修复前为 ENOTTY)", | ||
| EOPNOTSUPP, saved_errno, strerror(saved_errno)); | ||
| CHECK(saved_errno == EOPNOTSUPP, msg); | ||
|
|
||
| /* | ||
| * 未知接口名: 内核应先解析接口再判 ethtool, 因此返回 ENODEV 而非无条件 | ||
| * EOPNOTSUPP。固定与 Linux 一致的错误优先级, 也与本分支其它 SIOC*IF* 一致。 | ||
| */ | ||
| int fd2 = socket(AF_INET, SOCK_DGRAM, 0); | ||
| CHECK(fd2 >= 0, "socket(AF_INET, SOCK_DGRAM) 二次创建成功"); | ||
|
|
||
| struct ifreq bad; | ||
| memset(&bad, 0, sizeof bad); | ||
| strncpy(bad.ifr_name, "nonexist99", IFNAMSIZ - 1); | ||
| bad.ifr_data = (void *)ðcmd; | ||
|
|
||
| errno = 0; | ||
| int bad_ret = ioctl(fd2, SIOCETHTOOL, &bad); | ||
| int bad_errno = errno; | ||
| close(fd2); | ||
|
|
||
| snprintf(msg, sizeof msg, "SIOCETHTOOL 未知接口被拒 ret == -1 (实际 %d)", bad_ret); | ||
| CHECK(bad_ret == -1, msg); | ||
|
|
||
| snprintf(msg, sizeof msg, | ||
| "errno == ENODEV(%d) 接口校验先于 EOPNOTSUPP (实际 %d %s)", ENODEV, | ||
| bad_errno, strerror(bad_errno)); | ||
| CHECK(bad_errno == ENODEV, msg); | ||
|
|
||
| /* | ||
| * 合法接口但 ifr_data 是坏指针: 内核读取 ethtool 命令字时先 fault, 返回 | ||
| * EFAULT 而非 EOPNOTSUPP。错误优先级为 ENODEV -> EFAULT -> EOPNOTSUPP。 | ||
| */ | ||
| int fd3 = socket(AF_INET, SOCK_DGRAM, 0); | ||
| CHECK(fd3 >= 0, "socket(AF_INET, SOCK_DGRAM) 三次创建成功"); | ||
|
|
||
| struct ifreq faulty; | ||
| memset(&faulty, 0, sizeof faulty); | ||
| strncpy(faulty.ifr_name, "lo", IFNAMSIZ - 1); | ||
| faulty.ifr_data = (void *)1; | ||
|
|
||
| errno = 0; | ||
| int fault_ret = ioctl(fd3, SIOCETHTOOL, &faulty); | ||
| int fault_errno = errno; | ||
| close(fd3); | ||
|
|
||
| snprintf(msg, sizeof msg, "SIOCETHTOOL 坏 ifr_data 被拒 ret == -1 (实际 %d)", fault_ret); | ||
| CHECK(fault_ret == -1, msg); | ||
|
|
||
| snprintf(msg, sizeof msg, | ||
| "errno == EFAULT(%d) 坏指针先于 EOPNOTSUPP (实际 %d %s)", EFAULT, | ||
| fault_errno, strerror(fault_errno)); | ||
| CHECK(fault_errno == EFAULT, msg); | ||
|
|
||
| // 9 = 本文件 CHECK 总数。 | ||
| TEST_DONE(9); | ||
| } |
95 changes: 95 additions & 0 deletions
95
test-suit/starryos/qemu-smp1/system/syscall-test-ethtool-ioctl/src/test_framework.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| #pragma once | ||
|
|
||
| /* 必须在最前面定义,确保 pipe2/gettid 等可用 */ | ||
| #ifndef _GNU_SOURCE | ||
| #define _GNU_SOURCE | ||
| #endif | ||
|
|
||
| /* | ||
| * StarryOS Syscall Test Framework | ||
| * | ||
| * 极简独立测试框架:每个文件测一个 syscall,独立编译运行。 | ||
| * 目标:出错时精确定位到 源文件:行号 -> 哪个调用 -> 什么结果 | ||
| * | ||
| * 用法: | ||
| * TEST_START("测试名"); | ||
| * CHECK(call == expected, "描述"); | ||
| * CHECK_ERR(call, EBADF, "描述"); | ||
| * TEST_DONE(); | ||
| */ | ||
|
|
||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <errno.h> | ||
|
|
||
| static int __pass = 0; | ||
| static int __fail = 0; | ||
|
|
||
| /* ---- 核心: 带文件名+行号的检查宏 ---- */ | ||
|
|
||
| /* 检查条件为真 */ | ||
| #define CHECK(cond, msg) do { \ | ||
| if (cond) { \ | ||
| printf(" PASS | %s:%d | %s\n", __FILE__, __LINE__, msg); \ | ||
| __pass++; \ | ||
| } else { \ | ||
| printf(" FAIL | %s:%d | %s | errno=%d (%s)\n", \ | ||
| __FILE__, __LINE__, msg, errno, strerror(errno)); \ | ||
| __fail++; \ | ||
| } \ | ||
| } while(0) | ||
|
|
||
| /* 检查 syscall 返回特定值 */ | ||
| #define CHECK_RET(call, expected, msg) do { \ | ||
| errno = 0; \ | ||
| long _r = (long)(call); \ | ||
| long _e = (long)(expected); \ | ||
| if (_r == _e) { \ | ||
| printf(" PASS | %s:%d | %s (ret=%ld)\n", \ | ||
| __FILE__, __LINE__, msg, _r); \ | ||
| __pass++; \ | ||
| } else { \ | ||
| printf(" FAIL | %s:%d | %s | expected=%ld got=%ld | errno=%d (%s)\n", \ | ||
| __FILE__, __LINE__, msg, _e, _r, errno, strerror(errno));\ | ||
| __fail++; \ | ||
| } \ | ||
| } while(0) | ||
|
|
||
| /* 检查 syscall 失败且 errno 符合预期 */ | ||
| #define CHECK_ERR(call, exp_errno, msg) do { \ | ||
| errno = 0; \ | ||
| long _r = (long)(call); \ | ||
| if (_r == -1 && errno == (exp_errno)) { \ | ||
| printf(" PASS | %s:%d | %s (errno=%d as expected)\n", \ | ||
| __FILE__, __LINE__, msg, errno); \ | ||
| __pass++; \ | ||
| } else { \ | ||
| printf(" FAIL | %s:%d | %s | expected errno=%d got ret=%ld errno=%d (%s)\n", \ | ||
| __FILE__, __LINE__, msg, (int)(exp_errno), _r, errno, strerror(errno));\ | ||
| __fail++; \ | ||
| } \ | ||
| } while(0) | ||
|
|
||
| /* ---- 测试边界 ---- */ | ||
| #define TEST_START(name) \ | ||
| printf("================================================\n"); \ | ||
| printf(" TEST: %s\n", name); \ | ||
| printf(" FILE: %s\n", __FILE__); \ | ||
| printf("================================================\n") | ||
|
|
||
| /* | ||
| * 结束测试。expected = 本文件声明的 CHECK 总数。 | ||
| * 只有恰好跑满 expected 个检查且零失败才返回 0(成功); | ||
| * 零检查 / 少跑(早退/异常) / 有失败 一律返回 1(失败), | ||
| * 堵死"只跑部分模块也算过"的假阳性。 | ||
| */ | ||
| #define TEST_DONE(expected) \ | ||
| printf("------------------------------------------------\n"); \ | ||
| printf(" DONE: %d pass, %d fail, %d/%d checks run\n", \ | ||
| __pass, __fail, __pass + __fail, (expected)); \ | ||
| if ((__pass + __fail) != (expected)) \ | ||
| printf(" FAIL | %s:%d | ran %d check(s), expected %d\n", \ | ||
| __FILE__, __LINE__, __pass + __fail, (expected)); \ | ||
| printf("================================================\n\n"); \ | ||
| return ((__fail > 0) || ((__pass + __fail) != (expected))) ? 1 : 0 |
9 changes: 9 additions & 0 deletions
9
test-suit/starryos/qemu-smp1/system/syscall-test-mountinfo/CMakeLists.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| cmake_minimum_required(VERSION 3.20) | ||
| project(test-mountinfo C) | ||
| set(CMAKE_C_STANDARD 11) | ||
| set(CMAKE_C_STANDARD_REQUIRED ON) | ||
| set(CMAKE_C_EXTENSIONS OFF) | ||
| add_executable(test-mountinfo src/main.c) | ||
| target_include_directories(test-mountinfo PRIVATE src) | ||
| target_compile_options(test-mountinfo PRIVATE -Wall -Wextra -Werror) | ||
| install(TARGETS test-mountinfo RUNTIME DESTINATION usr/bin/starry-test-suit) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.