c - 마운트 - 단일 프로세스 인스턴스에서 여러 네트워크 네임 스페이스를 만드는 방법




마운트 네임 스페이스 (2)

하나의 프로세스 인스턴스 에서 여러 네트워크 네임 스페이스 를 만들려면 다음 C 함수를 사용하고 있습니다.

void create_namespace(const char *ns_name)
{
    char ns_path[100];

    snprintf(ns_path, 100, "%s/%s", "/var/run/netns", ns_name);
    close(open(ns_path, O_RDONLY|O_CREAT|O_EXCL, 0));
    unshare(CLONE_NEWNET);
    mount("/proc/self/ns/net", ns_path, "none", MS_BIND , NULL);
}

내 프로세스가 모든 네임 스페이스를 생성 한 후 하나의 네트워크 네임 스페이스에 tap 인터페이스를 추가 한 다음 ( ip link set tap1 netns ns1 명령을 사용하여) 모든 네임 스페이스에서이 인터페이스를 실제로 볼 수 있습니다 (아마도 이것은 실제로 단일 다른 이름으로 된 네임 스페이스).

그러나 다중 프로세스를 사용하여 여러 네임 스페이스를 작성하면 모든 것이 잘 작동합니다.

여기서 무엇이 잘못 될 수 있습니까? 단일 프로세스 인스턴스에서이 작업을 수행하려면 unshare() 에 추가 플래그를 전달해야합니까? 단일 프로세스 인스턴스가 여러 네트워크 네임 스페이스를 만들 수 없다는 제한이 있습니까? /proc/self/ns/net 가 실제로 여러 번 마운트되기 때문에 mount() 호출에 문제가 있습니까?

업데이트 : unshare() 함수는 여러 개의 네트워크 네임 스페이스를 올바르게 생성하지만 /var/run/netns/ 모든 마운트 지점은 실제로 해당 디렉토리에 마운트 된 첫 번째 네트워크 네임 스페이스를 참조합니다.

Update2 : 가장 좋은 방법은 다른 프로세스를 fork ()하고 거기에서 create_namespace () 함수를 실행하는 것입니다. 어쨌든, fork () 호출을 포함하지 않는 더 나은 솔루션을 듣거나 최소한 하나의 프로세스에서 여러 네트워크 네임 스페이스를 생성하고 관리하는 것이 불가능하다는 것을 확인하는 것이 좋을 것입니다.

Update3 : 다음 코드를 사용하여 unshare ()를 사용하여 여러 네임 스페이스를 만들 수 있습니다.

int  main() {
    create_namespace("a");
    system("ip tuntap add mode tap tapa");
    system("ifconfig -a");//shows lo and tapA interface
    create_namespace("b");
    system("ip tuntap add mode tap tapb");
    system("ifconfig -a");//show lo and tapB interface, but does not show tapA. So this is second namespace created.
}

하지만 프로세스가 종료되고 ip netns exec a ifconfig -aip netns exec b ifconfig -a 두 명령이 모두 네임 스페이스에서 갑자기 실행 된 것 같습니다. 실제 문제는 네임 스페이스에 대한 참조를 저장하는 것입니다 (또는 mount ()를 올바른 방법으로 호출하는 것입니다. 그러나 이것이 가능한지 확실하지 않습니다).


다른 프로세스에서이 네임 스페이스에 액세스해야하거나이 둘 사이를 앞뒤로 전환 할 수 있도록 핸들을 /proc/*/ns/* 하는 경우에만 mount /proc/*/ns/* 를 바인딩하면됩니다. 단일 프로세스에서 여러 네임 스페이스를 사용할 필요는 없습니다.

  • unshare 새로운 네임 스페이스를 만듭니다.
  • 복제 및 포크는 기본적으로 새 네임 스페이스를 만들지 않습니다.
  • 프로세스에 할당 된 각 종류의 하나의 "현재"네임 스페이스가 있습니다. 그것은 unshare 또는 setns에 의해 변경 될 수 있습니다. 네임 스페이스 집합은 (기본적으로) 자식 프로세스에 의해 상속됩니다.

열 때마다 ( /proc/N/ns/net ),이 파일에 대한 아이 노드가 생성되고 이후의 모든 open ()은 동일한 네임 스페이스에 바인드 된 파일을 반환합니다. 세부 정보는 커널 dentry 캐시의 깊이에서 손실됩니다.

또한 각 프로세스에는 /proc/self/ns/net 파일 항목이 하나만 있고 바인드 마운트는이 proc 파일의 새 인스턴스를 작성하지 않습니다. 마운트 된 파일을 여는 것은 /proc/self/ns/net 파일을 직접 여는 것과 똑같습니다 (처음 열 때 네임 스페이스를 가리키게됩니다).

" /proc/*/ns "는 이렇게 하프 - 굽는 것 같습니다.

따라서 네임 스페이스 만 필요하면 다음을 수행 할 수 있습니다.

  • open /proc/1/ns/net
  • 공유 취소
  • /proc/self/ns/net

둘 사이를 전환하십시오.

2 이상의 경우 clone() 해야 할 수도 있습니다 clone() . 프로세스 당 하나 이상의 /proc/N/ns/net 파일을 생성 할 방법이없는 것 같습니다.

그러나 런타임에 네임 스페이스간에 전환하거나 다른 프로세스와 공유 할 필요가없는 경우 다음과 같은 많은 네임 스페이스를 사용할 수 있습니다.

  • 소켓을 열고 메인 네임 스페이스에 대한 프로세스를 실행합니다.
  • 공유 취소
  • 소켓을 열고 두 번째 네임 스페이스 (netlink, tcp 등)에 대한 프로세스를 실행합니다.
  • 공유 취소
  • ...
  • 공유 취소
  • 네 번째 네임 스페이스 (netlink, tcp 등)에 대한 소켓 열기 및 프로세스 실행

오픈 소켓은 네트워크 네임 스페이스에 대한 참조를 유지하므로 소켓이 닫힐 때까지 수집되지 않습니다.

netlink를 사용하여 소스 네임 스페이스에서 netlink 명령을 보내고 PID 또는 네임 스페이스 FD (나중에없는 사용자)에서 dst 네임 스페이스를 지정하여 네임 스페이스간에 인터페이스를 이동할 수도 있습니다.

해당 네임 스페이스에 의존하는 /proc 항목에 액세스하기 전에 프로세스 네임 스페이스를 전환해야합니다. "proc"파일이 열리면 네임 스페이스에 대한 참조가 유지됩니다.


네트워크 네임 스페이스의도적 으로 복제 호출을 통해 만들어지며 공유 해제 후에 수정할 수 있습니다. 공유 하지 않고 새 네트워크 네임 스페이스를 만들더라도 실제로는 실행중인 프로세스의 네트워크 스택 만 수정하면됩니다. 공유 해제 는 다른 프로세스의 네트워크 스택을 수정할 수 없으므로 공유 해제 로만 다른 네트워크 스택을 작성할 수 없습니다.

새로운 네트워크 네임 스페이스가 작동하려면 새로운 네트워크 스택이 필요하므로 새로운 프로세스가 필요합니다. 그게 다야.

좋은 소식은 클론 과 함께 매우 가볍게 만들 수 있다는 것입니다.

Clone () 은 UNIX의 전통적인 fork () 시스템 호출과 달리 상위 및 하위 프로세스가 선택적으로 자원을 공유하거나 복제 할 수있게합니다.

이 네트워크 스택에서만 전환 할 수 있습니다 (메모리 공간, 파일 설명자 테이블 및 신호 처리기 테이블 제외). 새로운 네트워크 프로세스는 실제 포크 보다 더 많은 스레드 처럼 만들 수 있습니다.

C 코드 또는 Linux 커널 및 / 또는 LXC 도구를 사용하여 조작 할 수 있습니다.

예를 들어 새로운 네트워크 네임 스페이스에 장치를 추가하는 것은 간단합니다.

echo $PID > /sys/class/net/ethX/new_ns_pid

사용 가능한 CLI에 대한 자세한 내용은 이 페이지 를 참조하십시오.

C 측에서 lxc-unshare 구현을 살펴볼 수 있습니다. 그것의 이름에도 불구하고 당신 이 볼 수 있듯이 (lxc_clone은 here 있다.) 클론 을 사용한다. 저자가 포크를 직접 사용하도록 선택한 LTP 구현을 살펴볼 수도 있습니다.

편집 : 당신이 그들을 영원히 만들 수있는 트릭이 있지만, 당신은 여전히 ​​일시적으로 포크를해야합니다.

ipsource2 코드를 ipsource2 (명확성을 위해 오류 검사를 제거했습니다).

snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);

/* Create the base netns directory if it doesn't exist */
mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);

/* Create the filesystem state */
fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
[...]
close(fd);
unshare(CLONE_NEWNET);
/* Bind the netns last so I can watch for it */
mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL)

분기 된 프로세스에서이 코드를 실행하면 원하는대로 새 네트워크 네임 스페이스를 생성 할 수 있습니다. 그들을 삭제하기 위해서는 단순히이 바인드를 umount하고 삭제할 수 있습니다 :

umount2(netns_path, MNT_DETACH);
if (unlink(netns_path) < 0) [...]

EDIT2 : 또 다른 (더러운) 트릭은 "ip netns add .."cli를 시스템 과 함께 실행하는 것일뿐입니다.





linux-namespaces