1P by GN⁺ | ★ favorite | 댓글 1개
  • 만우절 발표로 시작된 Plan 9 지원은 실제 PR과 커널·Go 수정으로 이어졌고, 2025년 4월 2일 기준 Tailscale이 Plan 9에서 동작하는 상태까지 도달함
  • 단순한 GOOS=plan9 GOARCH=386 빌드 문제가 아니라, Go의 Plan 9 포트에서 런타임 크래시와 컴파일러 특수 처리 문제가 먼저 드러남
  • Russ Cox의 Plan 9 커널 및 Go 런타임·컴파일러 수정으로 SSE, 부동소수점 컨텍스트, 단조 시간, DNS, 개발 환경 문제가 함께 정리됨
  • Tailscale은 Plan 9의 /net 파일 인터페이스를 활용해 TUN 유사 구현, 라우팅, Tailscale SSH, MagicDNS, 서비스 수집을 붙였지만 일부는 임시 구현이거나 미완성임
  • 현재 검증 범위는 주로 9legacyGOARCH=386이며, 9front·amd64·exit node·Go net/netns 지원은 추가 검증이나 재설계가 필요함

만우절 농담이 실제 포팅으로 이어짐

  • Tailscale은 2025년 4월 1일 Plan 9 지원을 발표했고, 다음 날 이 발표가 실제 동작하는 포팅 작업을 바탕으로 했다는 배경을 공개함
  • 작업은 Tailscale PR과 여러 Plan 9·Go 수정으로 이어짐
  • 초기 접근은 Tailscale의 Go 바이너리 두 개를 GOOS=plan9 GOARCH=386 go install ./cmd/tailscale{,d}로 빌드하면 될 것이라는 기대에서 출발함
  • 2023년 8월 첫 시도에서는 일부 빌드가 진행됐지만 실행 중 비정상 크래시가 발생함
    • Go의 Plan 9 포트가 first-class port가 아니어서 회귀가 방치된 상태였음
    • Tailscale이 Plan 9에서 기존보다 Go를 더 강하게 밀어붙였을 가능성도 있음
  • 포팅은 2024년 내내 멈췄다가, 2025년 3월 만우절 아이디어와 함께 다시 진행됨

SSE와 Go의 Plan 9 지원 정리

  • 1999년 Intel Pentium III에 도입된 SSE 명령어가 이번 작업의 주요 출발점 중 하나였음
  • Go 컴파일러는 Plan 9 타깃에서 SSE 사용을 피하려고 했음
    • Plan 9 커널이 note handler에서 SSE 레지스터를 저장·복원하지 않았기 때문임
    • Go 컴파일러는 어떤 코드가 note handler 안에서 실행되는지 알 수 없어 SSE를 전역 비활성화하려 했음
    • 이 특수 처리는 자주 깨졌고, 컴파일러 곳곳에 plan9 예외가 많아짐
  • Russ Cox는 Plan 9 커널이 note handler에서 부동소수점·SIMD 컨텍스트를 다루도록 수정함
  • Go 쪽에서는 Plan 9 코드 생성 특수 처리 제거가 진행되면서 tailscaled가 더 오래 실행될 수 있게 됨

IPC와 개발 환경

  • 이후 tailscaled는 스택 손상 대신 메모리 부족으로 크래시하기 시작함
  • 이전 Plan 9 포팅 시도에서 Tailscale의 safesocket IPC 패키지에 무한히 goroutine을 만드는 버그가 있었음
  • 우선 localhost TCP를 쓰도록 바꾸면서 문제가 해결됨
    • Plan 9의 “모든 것이 파일” 방식에는 덜 어울리지만, 다른 Plan 9 서비스도 localhost TCP를 사용한다고 확인함
    • 향후에는 Russ가 Go로 포팅한 srv9p package를 이용해 LocalAPI를 얹는 방식이 더 나을 수 있음
    • 현재 구현은 다른 플랫폼처럼 localhost 인증을 붙이지 못하므로, 공유 Plan 9 머신에서는 쓰지 말라고 명시됨
  • 초기 개발은 9legacy CD 이미지 기반 VM에서 진행됐고, 바이너리를 HTTP로 내려받아 실행하는 반복 과정이 느렸음
  • Russ Cox가 만든 rsc/plan9은 Plan 9 소스, 사전 컴파일 바이너리, ./boot/qemu 스크립트를 포함함
    • qemu VM은 디스크 없이 부팅하고, localhost 9P 서버가 제공하는 Git 저장소를 루트 파일시스템으로 사용함
    • 개발 머신과 Plan 9 파일시스템을 공유해 반복 시간이 분 단위에서 초 단위로 줄어듦
    • qemu는 virtio도 사용해 더 빨라짐

네트워크 통합: TUN, 라우팅, MagicDNS

  • 처음 동작한 Tailscale은 커널 네트워크 스택을 쓰지 않는 사용자 공간 네트워킹 모드였음
    • TCP, UDP, ICMP 등은 gVisor의 netstack을 통해 처리됨
    • Plan 9 머신에서 tailnet으로 접근하려면 tailscaled의 HTTP/SOCKS5 프록시를 써야 함
    • Plan 9 프로그램 중 HTTP_PROXYALL_PROXY 환경 변수를 인식하는 경우가 거의 없어 이상적이지 않았음
  • Plan 9의 TUN 유사 구현은 매우 단순했음
    • /net/ipifc/clone을 열고 새 인터페이스 번호를 읽음
    • control fd에 "bind pkt\n"를 쓰면 /net/ipifc/2/* 같은 새 인터페이스가 생김
    • /net/ipifc/2/data를 열어 IP 패킷을 그대로 읽고 씀
    • 별도 ioctl이나 길이 프레이밍이 필요 없음
  • 라우팅 테이블 조작도 /net/iproute 파일을 통해 이뤄짐
    • "tag tail\n"을 써서 이후 추가되는 route에 tail 태그를 붙임
    • "add 100.64.0.0 /106 100.102.103.104" 같은 메시지로 route를 추가함
    • Plan 9 내부가 IPv6 중심이고 IPv4를 IPv4-mapped IPv6 주소로 다루기 때문에 CGNAT 100.64.0.0/10/106처럼 표현됨
  • MagicDNS는 Plan 9에서 peer를 foo 또는 foo.tailnet-name.ts.net 같은 이름으로 접근하게 만드는 작업이었음
    • /net/dns/net/cs 질의를 가로채는 방안도 논의됨
    • 최종적으로 Russ가 특정 DNS suffix에 대해 대체 DNS 서버를 지정할 수 있도록 Plan 9을 수정함
    • DNS 질의가 잘못 negative cache되는 문제도 수정

Tailscale SSH와 서비스 수집

  • Tailscale SSH는 tailscaled 내장 SSH 서버로, 패킷과 연결된 WireGuard 키를 통해 알려진 Tailscale identity로 인증함
  • 처음에는 Plan 9 셸인 /bin/rcos/exec.Command로 실행하고 stdin/stdout을 연결함
    • 셸은 실행됐지만 echo, 내비게이션, 프로세스 interrupt 등이 제대로 동작하지 않았음
  • Russ는 netshell example9fans/go에 추가함
    • 이 예제는 매우 안전하지 않은 telnet 서버에 가까웠지만, Tailscale SSH 뒤에 붙이기에는 충분했음
    • 이후 SSH로 Plan 9의 /dev/snarf 내용을 가져오거나, 노트북에서 Go 테스트를 cross-compile한 뒤 SSH로 실행하기 쉬워짐
  • Tailscale의 선택 기능인 서비스 수집도 Plan 9에 맞춰 검토됨
    • /proc/NNN/fd를 순회해 /net/tcp/clone을 연 프로세스를 찾음
    • fd의 QID를 /net/tcp/NNN/{status,local}와 맞춰 listening 여부와 포트를 확인함
    • QID에서 TCP 번호를 계산하는 방식은 커널 구현 변화에 취약해 아쉬운 부분으로 남음

시간, 웹 데모, v86

  • gVisor netstack이 단조 시간(monotonic time)이 뒤로 갔다고 보고하면서 tailscaled가 크래시하는 경우가 있었음
    • Go의 Plan 9 시간 구현이 단조 시간으로 wall time을 쓰고 있었음
    • ntpd가 시계를 뒤로 조정하면 netstack의 단조 시간 가정이 깨짐
  • Russ는 Plan 9의 /dev/bintime단조 시간을 추가하고, Go가 이를 사용하도록 수정
  • 웹에서 Plan 9을 실행하는 데는 v86이 사용됨
    • v86은 WASM으로 32비트 운영체제를 실행하고 여러 네트워크 방식을 제공함
    • 이 점도 GOARCH=386에 집중한 이유 중 하나였음
  • 처음에는 이더넷 프레임을 websocket relay로 보내기 위해 Tailscale의 네트워크 시뮬레이션 환경에 wsproxy protocol support를 추가함
    • ARP, DHCP, DNS, NAT, control plane, DERP 등을 gVisor netstack으로 흉내 내는 통합 테스트 환경에서 동작함
    • 하지만 DHCP 왕복 때문에 relay가 멀면 Plan 9 GUI인 rio 시작이 느려짐
  • 이후 WISP 서버도 구현했지만, 프로덕션화 전에 시간이 부족해 copy.sh/v86의 기본 네트워크 relay 설정으로 출시함
  • Tailscale과 Plan 9을 넣은 디스크 이미지는 16MB였고, Tailscale 바이너리는 압축 해제 후 23MB였음
    • 부팅 시 “gunzip…” 단계가 보이는 이유가 여기에 있음
    • 예제 이미지는 copy.sh/v86의 9legacy 프로필에 포함됨

남은 작업과 실제 성과

댓글과 토론

Hacker News 의견들
  • 궁금한 게 있으면 답할 수 있음
    지금 몇 명이 https://meet.google.com/qre-gydb-mkv에서 이 얘기를 나누고 있음
    편집: 한 시간이 지나서 모두 나갔음
    이전 4월 1일 블로그 글https://tailscale.com/blog/tailscale-enterprise-plan-9-suppo...였음

    • Plan 9 시스템을 한 번도 설정해 본 적이 없는데, 이걸 쓰면 분산 시스템 통신이 내 Tailnet을 통해 지나가게 할 수 있는 건가?
  • Russ Cox가 이 농담을 끝까지 밀어붙인 건 정말 전설적

    • 누가 Russ를 설득해서 Plan 9에 완전한 웹 브라우저를 넣으면 엄청 웃길 거라고 해줬으면 함
  • 9fans 목록에는 만우절용으로 이런 게 올라왔음
    mips, 386, arm, arm64, amd64 같은 미성숙한 컴퓨터 아키텍처의 유지보수 비용이 너무 커서, 더 성숙하고 안정적인 아키텍처에 집중하기로 했다는 내용임
    그 대상은 power64와 itanium이고, 따라서 power64와 itanium을 제외한 모든 아키텍처는 동결·보존되며 수명 종료로 승격된다고 함

  • 농담이 아니라 진짜로 Plan 9 엔터프라이즈 버전이 있었으면 좋겠음
    요즘 스크립트 대부분을 rc로 쓰고 있는데, 우리가 nix를 쓰고 dirnev로 자동으로 끌어올 수 있어서 동료들이 참고 넘어가 주는 중이고, 꽤 좋았음

    • 다른 사람들이 rc 스크립트를 실행할 수 있는지보다, 그걸 읽고 수정할 수 있는지를 더 걱정할 것 같음
    • rc의 장점 하나는 이거임[1]:
      “rc 설계에서 가장 중요한 원칙은 매크로 처리기가 아니라는 점이다. 입력은 어휘·구문 분석 코드에서 절대 두 번 이상 스캔되지 않는다”
      예전에 일하던 유닉스 회사에서 실행 중이던 셸 스크립트가 수정되는 바람에 작업 디스크 대부분을 지운 적이 있음. 다행히 일일 백업을 테이프에 보관하고 있었고, 대략 17년 전 일이었음
      [1] https://www.scs.stanford.edu/nyu/04fa/sched/readings/rc.pdf
    • 엔터프라이즈 Plan 9”에서 구체적으로 뭘 기대하는지 더 설명해 줄 수 있나?
  • 첫 글에서 놓쳤고 그냥 직접 시험해 보고 싶다면, 이 v86 이미지에서 동작함:
    https://copy.sh/v86/?profile=custom&m=768&vram=16&hda.url=ht...
    VM 안에서 tailscaledtailscale을 시작할 수 있음. 프록시 가용성이 제한적이라 온라인 상태가 되기까지 시간이 좀 걸릴 수 있음
    편집: alt가 세 번째 버튼 역할을 함. 터미널을 시작하려면 alt를 누른 채 오른쪽 클릭, new 선택, alt에서 손을 떼고 오른쪽 클릭 드래그로 터미널 창 크기를 조절하면 됨

  • 웨비나 진행 중임(Google Meet) https://ftp.plan9.ts.net/webinar

    • 관심 있었을 사람들을 위해 말하자면, 방금 끝났음
  • 농담의 전제는 마음에 들었는데, 설명이 길어질수록 갑자기 우울해졌음
    망가진 게 너무 많고 복잡도도 너무 큼. 결국 뭘 위해서인가, 네트워크 터널 하나 만들려고? 이 추가 작업 자체가 농담이었다면 웃겼을 듯함

    • 새 작업을 하려면 Plan 9 쪽 작업이 조금 필요했지만, 실제 Tailscale 구현은 다른 유닉스들보다 훨씬 작업량이 적었음
    • 이 작업 덕분에 Go 컴파일러도 더 좋아진 것처럼 들림. 코드 안의 Plan 9 특수 처리가 줄었으니까
  • rsc, rob pike, bradfitz와는 특히 Plan 9 얘기로 몇 시간이고 붙잡고 이야기할 수 있을 것 같음. 물론 그들의 시간을 완전히 낭비하게 되겠지만
    그 운영체제는 정말 매혹적임
    커리어 초반에 같이 일하던 전문가가 옆에 앉아서, 내가 충분히 이해할 때까지 참을성 있게 방법을 보여주고 질문을 받아주던 때가 기억남. 깊은 물에 빠져도 헤엄칠 수 있게 만들어 주는 식이었고, 세 시간 만에 특정 지식으로 학사 학위 하나를 받은 듯한, 커리어에서 가장 빠른 성장 중 하나였음
    C도 모르고 Plan 9도 생산적으로 쓸 만큼 알지는 못하지만, 지금의 주요 3대 운영체제에는 없는 걸 아쉬워하기 위해서라도 더 알고 배우고 싶은 멋지고 유용한 기능들이 있음
    돈이 있다면 Go 지식을 넓히려고 세 사람 모두와 직접 이야기할 시간을 사고, 늘 원했지만 스스로 얻지 못했던 Plan 9 이해를 위해 rsc와 rob pike의 시간도 사고 싶음

  • Plan 9가 정말 좋음. 그 원칙을 많이 가져와서 내 운영체제를 만드는 게 은퇴 프로젝트이자 인생 목표임
    편집: 이 프로젝트 이름은 “chaos10”으로 예약해 둠. SerenityOS처럼 계획은 없을 테니까

  • 이게 동작하게 하려고 Plan 9 커널까지 패치할 줄은 전혀 예상 못 했음

    • 왜 아니겠나? 아무도 이런 걸 진지하게 해본 적이 없었던 게 분명하니, 빠져 있던 작업량은 비교적 적어 보임 :)