/proc/net/stat
다른 네임스페이스에서 애플리케이션에 액세스할 수 있도록 하는 방법이 있나요 ?
분명한 것은 애플리케이션(즉, 프로세스)을 해당 netns에 넣는 것입니다. 그러나 제가 염두에 두고 있는 것은 애플리케이션이 통계를 모니터링 /proc/net/stat
하고 이를 네트워크를 통해 데이터베이스로 전달해야 한다는 것입니다. 그러나 데이터베이스는 단지 경로일 뿐입니다. 기본 네임스페이스에서 가능합니다.
비슷한 길이 있을 거라 기대했지만 /proc/namespace-root/foo/net/stat
그렇지 않았습니다.
또한 다른 네임스페이스의 임의 PID에 의존하고 /proc/$somePID/ns/net
.
답변1
프로세스에 다른 네트워크 네임스페이스를 제공합니다.
$ ps aux | grep '[s]leep'
root 716080 0.4 0.0 2292 748 ? Ss 19:09 0:00 sleep 24h
$ sudo ls -l /proc/$$/ns/net /proc/716080/ns/net
lrwxrwxrwx 1 user group 0 Jul 14 19:11 /proc/715845/ns/net -> 'net:[4026531992]'
lrwxrwxrwx 1 root root 0 Jul 14 19:09 /proc/716080/ns/net -> 'net:[4026532200]'
방법 1
나는 그것이 무엇인지 모릅니다 /proc/net/stats
. 나는 그것을 가지고 있지 않습니다. 그래서 /proc/net/stat/nf_conntrack
대신 이 예를 사용하겠습니다. 기본 네임스페이스의 파일을 보면 다음과 같습니다.
$ cat /proc/net/stat/nf_conntrack
entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete search_restart
00000001 00000000 00000000 00000000 00000000 000000b8 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000001 00000000 00000000 00000000 00000002 00000087 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
이 nsenter
명령을 사용하여 다양한 네임스페이스에서 명령을 실행할 수 있습니다. 여기에서 cat
대상 프로세스의 네트워크 네임스페이스에서 실행할 수 있습니다 .
$ sudo nsenter --net=/proc/716080/ns/net cat /proc/net/stat/nf_conntrack
entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete search_restart
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
자세히 살펴보면 값이 다르다는 것을 알 수 있습니다. nsenter
사용된 결과는 대상 프로세스의 네트워크 네임스페이스에 있는 proc 파일의 내용입니다.
방법 2
OP는 측정항목 수집 애플리케이션의 맥락에서 작동하는 솔루션을 찾고 있습니다. 원하는 결과를 얻을 수 있는 다음 샘플 애플리케이션을 구성했습니다.
#define _GNU_SOURCE
#include <fcntl.h>
#include <limits.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
if (argc < 2) {
fprintf(stderr, "Usage: %s <pid>\n", argv[0]);
return 1;
}
int pipe_fds[2] = {};
if (pipe(pipe_fds) < 0) {
perror("pipe");
return 2;
}
const pid_t pid = fork();
if (pid < 0) {
perror("fork");
return 3;
}
if (pid == 0) { // child
char file_path[PATH_MAX];
if (dup2(pipe_fds[1], STDOUT_FILENO) < 0) {
perror("dup2");
return 4;
}
close(pipe_fds[0]);
close(pipe_fds[1]);
snprintf(file_path, sizeof(file_path) - 1, "/proc/%s/ns/net", argv[1]);
const int fd = open(file_path, O_RDONLY);
if (fd < 0) {
perror("open");
return 5;
}
if (setns(fd, CLONE_NEWNET) < 0) {
perror("setns");
return 6;
}
FILE* const proc_file = fopen("/proc/net/stat/nf_conntrack", "r");
if (proc_file == NULL) {
fprintf(stderr, "fopen failed\n");
return 7;
}
char* line = NULL;
size_t line_len = 0;
while (getline(&line, &line_len, proc_file) != -1) {
printf("%s", line);
}
free(line);
fclose(proc_file);
return 0; // Child process is done
}
// parent
if (dup2(pipe_fds[0], STDIN_FILENO) < 0) {
perror("dup2");
return 8;
}
close(pipe_fds[0]);
close(pipe_fds[1]);
char* line = NULL;
size_t line_len = 0;
while (getline(&line, &line_len, stdin) != -1) {
printf("%s", line);
}
free(line);
// Clean up our dead child
wait(NULL);
return 0;
}
애플리케이션은 기본 네트워크 네임스페이스에서 시작됩니다. 여기에는 하나의 명령줄 인수(대상 네트워크 네임스페이스에 있는 프로세스의 PID)가 필요합니다.
프로그램은 파이프를 생성한 다음 분기합니다. 하위 프로세스는 표준 출력을 파이프의 쓰기 끝에 연결합니다. 상위는 표준 입력을 파이프의 읽기 끝에 연결합니다.
자식 프로세스는 proc 파일을 사용하여 대상 프로세스의 네트워크 네임스페이스를 연 다음 시스템 setns()
호출을 사용하여 해당 네트워크 네임스페이스를 대상 프로세스의 네트워크 네임스페이스로 전환합니다. 그런 다음 하위 프로세스는 /proc
파일을 열고 한 줄씩 읽고 결과를 표준 출력(여기서는 파이프)에 씁니다.
부모는 표준 입력(파이프)에서 줄을 읽고 이 줄을 표준 출력에 씁니다.
여기서 상위 프로세스는 메트릭 수집 애플리케이션의 역할을 수행할 수 있습니다. 기본 네트워크 네임스페이스에 남아 있으며 읽은 값을 전달하기 위해 기본 네트워크 네임스페이스의 컨텍스트에서 일부 원격 네트워크 호스트에 연결할 수 있습니다.
- 기반 접근 방식 은 fork()
유일한 옵션이 아니며 단지 내가 사용하는 방식일 뿐입니다.
프로그램 실행:
$ sudo ./a.out 716080
entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete search_restart
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
$