1 คะแนน โดย GN⁺ 2025-04-03 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • การรองรับ Plan 9 ที่เริ่มจากประกาศวันเมษาหน้าโง่ ได้ต่อยอดเป็น PR จริงและการแก้ไขเคอร์เนล·Go จนถึงสถานะที่ Tailscale ทำงานบน Plan 9 ได้ ณ วันที่ 2 เมษายน 2025
  • นี่ไม่ใช่แค่ปัญหาการบิลด์ด้วย GOOS=plan9 GOARCH=386 เท่านั้น แต่ใน Plan 9 port ของ Go ยังพบทั้งปัญหา runtime crash และการจัดการกรณีพิเศษในคอมไพเลอร์ก่อน
  • การแก้ไขเคอร์เนล Plan 9 และ runtime·compiler ของ Go โดย Russ Cox ช่วยสะสางเรื่อง SSE, floating-point context, monotonic time, DNS และสภาพแวดล้อมสำหรับพัฒนาไปพร้อมกัน
  • Tailscale ใช้อินเทอร์เฟซไฟล์ /net ของ Plan 9 เพื่อต่อ การทำงานคล้าย TUN, routing, Tailscale SSH, MagicDNS และ service discovery เข้าด้วยกัน แต่บางส่วนยังเป็นการทำแบบชั่วคราวหรือยังไม่สมบูรณ์
  • ขอบเขตการทดสอบตอนนี้ยังอยู่ที่ 9legacy และ GOARCH=386 เป็นหลัก ส่วน 9front·amd64·exit node·การรองรับ Go net/netns ยังต้องมีการทดสอบเพิ่มหรือออกแบบใหม่

มุกวันเมษาหน้าโง่ที่กลายเป็นงานพอร์ตจริง

  • Tailscale ประกาศรองรับ Plan 9 เมื่อวันที่ 1 เมษายน 2025 และวันถัดมาก็เปิดเผยเบื้องหลังว่าประกาศนี้อ้างอิงจากงานพอร์ตที่ใช้งานได้จริง
  • งานนี้ต่อยอดไปเป็น Tailscale PR และการแก้ไขต่าง ๆ ใน Plan 9·Go
  • แนวทางแรกเริ่มมาจากความคาดหวังว่า หากบิลด์ Go binary ของ Tailscale สองตัวด้วย GOOS=plan9 GOARCH=386 go install ./cmd/tailscale{,d} ก็น่าจะเพียงพอ
  • ในความพยายามครั้งแรกเมื่อเดือนสิงหาคม 2023 แม้บางส่วนจะบิลด์ได้ แต่ระหว่างรันกลับเกิดการ crash แบบผิดปกติ
    • เพราะ Plan 9 port ของ Go ไม่ได้เป็น first-class port จึงมี regression ที่ถูกปล่อยค้างไว้
    • อีกความเป็นไปได้คือ Tailscale ไปใช้งาน Go บน Plan 9 หนักกว่าที่เคยมีมาก่อน
  • งานพอร์ตหยุดชะงักตลอดปี 2024 ก่อนจะกลับมาเดินต่ออีกครั้งพร้อมไอเดียวันเมษาหน้าโง่ในเดือนมีนาคม 2025

การสะสาง SSE และการรองรับ Plan 9 ใน Go

  • คำสั่ง SSE ที่ถูกนำมาใช้ครั้งแรกใน Intel Pentium III เมื่อปี 1999 เป็นหนึ่งในจุดตั้งต้นสำคัญของงานนี้
  • คอมไพเลอร์ Go พยายามหลีกเลี่ยงการใช้ SSE เมื่อ target เป็น Plan 9
    • เพราะเคอร์เนล Plan 9 ไม่ได้บันทึก·กู้คืนรีจิสเตอร์ SSE ใน note handler
    • คอมไพเลอร์ Go ไม่สามารถรู้ได้ว่าโค้ดใดจะถูกรันใน note handler จึงพยายามปิด SSE แบบทั้งระบบ
    • การจัดการกรณีพิเศษนี้พังบ่อย และทำให้มีข้อยกเว้น plan9 กระจายอยู่ทั่วคอมไพเลอร์
  • Russ Cox แก้เคอร์เนล Plan 9 ให้จัดการ floating-point·SIMD context ใน note handler ได้
    • ฝั่ง 386 มีการแก้ไข sys/src/9: allow floating point in note handlers
    • ในเคอร์เนล amd64 9k ยังพบปัญหาเพิ่มเติม เช่น FP state aliasing หลัง fork, SIMD ใน note handler และการสูญหายของรีจิสเตอร์ใน noted(NCONT)
  • ฝั่ง Go มีการดำเนินการ ลบการจัดการกรณีพิเศษในการสร้างโค้ดสำหรับ Plan 9 ทำให้ tailscaled รันได้นานขึ้น

IPC และสภาพแวดล้อมสำหรับพัฒนา

  • หลังจากนั้น tailscaled เริ่ม crash ด้วย หน่วยความจำไม่พอ แทนที่จะเป็น stack corruption
  • ในความพยายามพอร์ต Plan 9 ก่อนหน้านี้ พบว่ามีบั๊กในแพ็กเกจ IPC safesocket ของ Tailscale ที่สร้าง goroutine แบบไม่สิ้นสุด
  • จึงแก้เฉพาะหน้าด้วยการเปลี่ยนไปใช้ localhost TCP และปัญหาก็หายไป
    • แม้จะไม่ค่อยเข้ากับแนวคิด “ทุกอย่างคือไฟล์” ของ Plan 9 แต่ก็ยืนยันได้ว่าบริการอื่นบน Plan 9 ก็ใช้ localhost TCP เช่นกัน
    • ในอนาคต วิธีที่ดีกว่าอาจเป็นการวาง LocalAPI บน srv9p package ที่ Russ พอร์ตมาเป็น Go
    • ตอนนี้ implementation ยังใส่การยืนยันตัวตนบน localhost แบบแพลตฟอร์มอื่นไม่ได้ จึงระบุชัดว่าไม่ควรใช้บนเครื่อง Plan 9 ที่ใช้ร่วมกัน
  • งานพัฒนาช่วงแรกทำบน VM ที่ใช้ 9legacy CD image และการดาวน์โหลด binary ผ่าน HTTP มารันซ้ำ ๆ ค่อนข้างช้า
  • rsc/plan9 ที่ Russ Cox ทำไว้ มีทั้ง source ของ Plan 9, binary ที่คอมไพล์ไว้ล่วงหน้า และสคริปต์ ./boot/qemu
    • qemu VM บูตแบบไม่มีดิสก์ และใช้ Git repository ที่ 9P server บน localhost ให้บริการเป็น root filesystem
    • การแชร์ filesystem ระหว่างเครื่องพัฒนากับ Plan 9 ช่วยลดเวลาวนรอบจากระดับนาทีเหลือระดับวินาที
    • qemu ยังใช้ virtio ด้วย จึงทำงานได้เร็วขึ้นอีก

การผนวกเครือข่าย: TUN, routing, MagicDNS

  • Tailscale เวอร์ชันแรกที่ทำงานได้ ใช้โหมด user-space networking ซึ่งไม่พึ่ง kernel network stack
    • TCP, UDP, ICMP ฯลฯ ถูกจัดการผ่าน netstack ของ gVisor
    • หากต้องการเข้าถึง tailnet จากเครื่อง Plan 9 ต้องใช้ HTTP/SOCKS5 proxy ของ tailscaled
    • แต่วิธีนี้ไม่เหมาะนัก เพราะโปรแกรมบน Plan 9 แทบไม่มีตัวไหนรู้จักตัวแปรสภาพแวดล้อม HTTP_PROXY หรือ ALL_PROXY
  • การทำงานคล้าย TUN ของ Plan 9 นั้นเรียบง่ายมาก
    • เปิด /net/ipifc/clone แล้วอ่านหมายเลขอินเทอร์เฟซใหม่
    • เขียน "bind pkt\n" ไปยัง control fd แล้วจะมีอินเทอร์เฟซใหม่อย่าง /net/ipifc/2/* ปรากฏขึ้น
    • เปิด /net/ipifc/2/data เพื่ออ่านและเขียนแพ็กเก็ต IP ได้โดยตรง
    • ไม่ต้องมี ioctl แยกหรือการ framing ความยาวข้อมูล
  • การจัดการ routing table ก็ทำผ่านไฟล์ /net/iproute
    • เขียน "tag tail\n" เพื่อใส่แท็ก tail ให้ route ที่เพิ่มหลังจากนั้น
    • เพิ่ม route ด้วยข้อความอย่าง "add 100.64.0.0 /106 100.102.103.104"
    • เพราะภายใน Plan 9 เน้น IPv6 และจัดการ IPv4 เป็น IPv4-mapped IPv6 address ทำให้ CGNAT 100.64.0.0/10 ถูกแสดงเป็น /106
  • งานของ MagicDNS บน Plan 9 คือทำให้เข้าถึง peer ได้ด้วยชื่ออย่าง foo หรือ foo.tailnet-name.ts.net
    • เคยมีการพูดถึงแนวทางดัก query ที่ /net/dns หรือ /net/cs
    • สุดท้าย Russ แก้ Plan 9 ให้กำหนด DNS server ทางเลือกสำหรับ DNS suffix บางตัวได้
    • ปัญหาที่ DNS query ถูก negative cache ผิดพลาดก็ถูกแก้ไขเช่นกัน

Tailscale SSH และ service discovery

  • Tailscale SSH คือ SSH server ที่ฝังอยู่ใน tailscaled และยืนยันตัวตนด้วย Tailscale identity ที่รู้จักจาก WireGuard key ที่ผูกกับแพ็กเก็ต
  • ตอนแรกใช้ os/exec.Command เรียกเชลล์ Plan 9 คือ /bin/rc แล้วต่อ stdin/stdout เข้าด้วยกัน
    • แม้เชลล์จะรันได้ แต่การ echo, การเลื่อนตำแหน่ง, และการ interrupt process ทำงานได้ไม่ถูกต้อง
  • Russ เพิ่ม netshell example เข้าไปใน 9fans/go
    • ตัวอย่างนี้ใกล้เคียงกับ telnet server ที่ไม่ปลอดภัยมาก แต่ก็เพียงพอเมื่ออยู่หลัง Tailscale SSH
    • หลังจากนั้นก็ทำสิ่งอย่างดึงข้อมูลจาก /dev/snarf ของ Plan 9 ผ่าน SSH หรือ cross-compile Go test จากโน้ตบุ๊กแล้วสั่งรันผ่าน SSH ได้ง่ายขึ้น
  • ฟีเจอร์เสริมของ Tailscale อย่าง service discovery ก็ถูกพิจารณาให้เหมาะกับ Plan 9 ด้วย
    • วนดู /proc/NNN/fd เพื่อหา process ที่เปิด /net/tcp/clone
    • จับคู่ QID ของ fd กับ /net/tcp/NNN/{status,local} เพื่อตรวจว่ากำลัง listen อยู่หรือไม่และใช้พอร์ตใด
    • วิธีคำนวณหมายเลข TCP จาก QID ยังน่ากังวล เพราะเปราะบางต่อการเปลี่ยน implementation ของเคอร์เนล

เวลา, เว็บเดโม, v86

  • เคยมีกรณีที่ tailscaled crash เพราะ gVisor netstack รายงานว่า monotonic time ถอยหลัง
    • implementation เวลาใน Go สำหรับ Plan 9 ใช้ wall time เป็น monotonic time
    • เมื่อ ntpd ปรับนาฬิกาย้อนกลับ สมมติฐานของ netstack เกี่ยวกับ monotonic time ก็พัง
  • Russ เพิ่ม monotonic time เข้าไปใน /dev/bintime ของ Plan 9 และแก้ให้ Go ใช้มัน
  • การรัน Plan 9 บนเว็บใช้ v86
    • v86 รันระบบปฏิบัติการ 32 บิตด้วย WASM และมีวิธีเครือข่ายหลายแบบให้ใช้
    • นี่ก็เป็นอีกเหตุผลที่เน้นไปที่ GOARCH=386
  • ตอนแรกมีการเพิ่ม wsproxy protocol support เข้าไปในสภาพแวดล้อมจำลองเครือข่ายของ Tailscale เพื่อส่ง Ethernet frame ผ่าน websocket relay
    • มันทำงานอยู่ในสภาพแวดล้อม integration test ที่จำลอง ARP, DHCP, DNS, NAT, control plane, DERP ฯลฯ ด้วย gVisor netstack
    • แต่เพราะมีรอบรับส่ง DHCP ถ้า relay อยู่ไกล การเปิด rio ซึ่งเป็น GUI ของ Plan 9 จะช้า
  • ต่อมามีการทำ WISP server ด้วยเช่นกัน แต่เวลาไม่พอจะทำให้พร้อมใช้งานจริงก่อนเปิดตัว จึงปล่อยด้วยการตั้งค่า network relay เริ่มต้นของ copy.sh/v86
  • disk image ที่รวม Tailscale และ Plan 9 มีขนาด 16MB ส่วน binary ของ Tailscale มีขนาด 23MB หลังแตกไฟล์
    • นี่คือเหตุผลที่เห็นขั้นตอน “gunzip…” ตอนบูต
    • image ตัวอย่างถูกใส่ไว้ในโปรไฟล์ 9legacy ของ copy.sh/v86

งานที่ยังเหลือและผลลัพธ์ที่เกิดขึ้นจริง

  • ตอนนี้งานพอร์ต Tailscale ไปยัง Plan 9 ถูกทดสอบบน 9legacy เท่านั้น
    • fork หลักของ Plan 9 มีทั้ง 9legacy ที่ใกล้เคียงต้นฉบับ และ 9front ที่ถูกปรับแก้มากกว่า
    • แพตช์บางส่วนที่ Russ เขียนให้ 9legacy อาจต้องพอร์ตไปยัง 9front ด้วย
  • การรองรับ 64 บิตด้วย GOARCH=amd64 ก็ยังต้องตรวจสอบเพิ่มเติม
  • ยังไม่มีการทำ exit node และการรองรับแพ็กเกจ Go net/netns
    • เพื่อทำสิ่งนี้ อาจต้องกลับมาทบทวนแนวทาง เช่น ให้ Tailscale แสดงตัวเองเป็น /net แยกต่างหากบน Plan 9
  • งานนี้ยังช่วยยกระดับการรองรับ Plan 9 ใน Go ด้วย
  • โดยเฉพาะการลบการจัดการกรณีพิเศษของ Plan 9 ออกจากคอมไพเลอร์ Go ทำให้คอมไพเลอร์เรียบง่ายขึ้นและแก้ไขได้ง่ายขึ้น
  • ตอนเผยแพร่เดโม v86 ยังมีมุกวันเมษาหน้าโง่จากผู้สร้าง v86 ที่ทำให้แม้แต่ข้อความ VGA ก็แสดงเป็นภาษาดัตช์ปลอม ๆ แต่หลีกเลี่ยงได้ด้วย query argument &nojoke

1 ความคิดเห็น

 
GN⁺ 2025-04-03
ความคิดเห็นจาก Hacker News
  • ถ้ามีอะไรสงสัย ผมตอบได้
    ตอนนี้มีคนไม่กี่คนกำลังคุยเรื่องนี้กันที่ https://meet.google.com/qre-gydb-mkv
    แก้ไข: ผ่านไปหนึ่งชั่วโมง ทุกคนออกไปหมดแล้ว
    บล็อกโพสต์ วันที่ 1 เมษายน ก่อนหน้านี้คือ https://tailscale.com/blog/tailscale-enterprise-plan-9-suppo...

    • ผมไม่เคยตั้งค่าระบบ Plan 9 มาก่อนเลย ถ้าใช้อันนี้จะทำให้ การสื่อสารของระบบแบบกระจาย วิ่งผ่าน Tailnet ของผมได้ไหม?
  • การที่ Russ Cox ผลักมุกนี้ไปจนสุดทางนี่ ระดับตำนาน จริง ๆ

    • อยากให้ใครสักคนไปโน้มน้าว Russ ว่าถ้าใส่ เว็บเบราว์เซอร์เต็มรูปแบบ ลงใน Plan 9 ได้คงฮาสุด ๆ
  • ในลิสต์ 9fans มีเรื่องแบบนี้โพสต์ไว้สำหรับวัน April Fools’
    เนื้อหาคือค่าใช้จ่ายในการดูแลสถาปัตยกรรมคอมพิวเตอร์ที่ยังไม่สุกงอมอย่าง mips, 386, arm, arm64, amd64 นั้นสูงเกินไป จึงตัดสินใจไปโฟกัสกับสถาปัตยกรรมที่เติบโตและเสถียรกว่า
    เป้าหมายนั้นคือ power64 และ itanium ดังนั้นสถาปัตยกรรมทั้งหมดนอกจาก power64 และ itanium จะถูกแช่แข็ง·เก็บรักษา และเลื่อนสถานะเป็นสิ้นสุดอายุการใช้งาน

  • ไม่ได้ล้อเล่นนะ ผมอยากให้มี Plan 9 เวอร์ชัน enterprise จริง ๆ
    ช่วงนี้สคริปต์ส่วนใหญ่ผมเขียนด้วย rc และเพราะเราใช้ nix กับดึงเข้ามาอัตโนมัติด้วย dirnev ได้ เพื่อนร่วมงานเลยยอม ๆ ให้ผ่านไป ซึ่งก็ดีทีเดียว

    • ผมคงกังวลมากกว่าว่าคนอื่นจะ อ่านและแก้ไข สคริปต์ rc ได้ไหม ไม่ใช่ว่าจะรันมันได้ไหม
    • ข้อดีอย่างหนึ่งของ rc คือสิ่งนี้[1]:
      “หลักการสำคัญที่สุดในการออกแบบ rc คือมันไม่ใช่ macro processor อินพุตจะไม่ถูกสแกนเกินหนึ่งครั้งโดยโค้ดวิเคราะห์ศัพท์และไวยากรณ์เด็ดขาด”
      สมัยก่อนตอนทำงานที่บริษัทยูนิกซ์แห่งหนึ่ง มีสคริปต์เชลล์ที่กำลังรันอยู่ถูกแก้ไข จนลบดิสก์งานส่วนใหญ่ไป โชคดีที่เรามีแบ็กอัปรายวันเก็บไว้ในเทป และเรื่องนั้นก็ประมาณ 17 ปีก่อนแล้ว
      [1] https://www.scs.stanford.edu/nyu/04fa/sched/readings/rc.pdf
    • ช่วยอธิบายเพิ่มได้ไหมว่าคาดหวังอะไรเป็นรูปธรรมจาก “Plan 9 ระดับ enterprise”?
  • ถ้าพลาดโพสต์แรกไปและแค่อยากลองเอง มันทำงานได้ใน อิมเมจ v86 นี้:
    https://copy.sh/v86/?profile=custom&m=768&vram=16&hda.url=ht...
    ใน VM สามารถเริ่ม tailscaled และ tailscale ได้ ความพร้อมใช้งานของพร็อกซีมีจำกัด เลยอาจใช้เวลาสักหน่อยกว่าจะออนไลน์
    แก้ไข: alt ทำหน้าที่เป็นปุ่มที่สาม ถ้าจะเปิดเทอร์มินัล ให้กด alt ค้างไว้แล้วคลิกขวา เลือก new จากนั้นปล่อย alt แล้วลากด้วยคลิกขวาเพื่อปรับขนาดหน้าต่างเทอร์มินัล

  • กำลังมี webinar อยู่ (Google Meet) https://ftp.plan9.ts.net/webinar

    • เผื่อคนที่สนใจ ตอนนี้เพิ่งจบไปแล้ว
  • ผมชอบ premise ของมุกนี้นะ แต่ยิ่งอธิบายยาวขึ้นก็ยิ่งรู้สึกหดหู่ขึ้นมา
    มีของที่พังเยอะเกินไป และความซับซ้อนก็มากเกินไป สุดท้ายเพื่ออะไร แค่ทำ network tunnel อันเดียวเหรอ? ถ้างานเพิ่มเติมพวกนี้เองคือมุก ก็คงตลกดี

    • การทำงานใหม่ต้องมีงานฝั่ง Plan 9 นิดหน่อย แต่ การ implement Tailscale จริง ๆ ใช้งานน้อยกว่ายูนิกซ์อื่น ๆ มาก
    • ฟังดูเหมือนงานนี้ทำให้คอมไพเลอร์ Go ดีขึ้นด้วย เพราะ การจัดการพิเศษสำหรับ Plan 9 ในโค้ดลดลง
  • ผมคงคุยกับ rsc, rob pike, bradfitz ได้เป็นชั่วโมง ๆ โดยเฉพาะเรื่อง Plan 9 แน่นอนว่าคงเป็นการเสียเวลาของพวกเขาไปโดยสิ้นเชิง
    ระบบปฏิบัติการนั้นชวนหลงใหลจริง ๆ
    ผมนึกถึงช่วงต้นอาชีพที่มีผู้เชี่ยวชาญซึ่งทำงานด้วยกันมานั่งข้าง ๆ ค่อย ๆ แสดงวิธีทำและตอบคำถามอย่างอดทนจนกว่าผมจะเข้าใจพอ เป็นเหมือนการทำให้ว่ายน้ำได้แม้ถูกโยนลงน้ำลึก และในสามชั่วโมงก็เหมือนได้ปริญญาตรีหนึ่งใบในความรู้เฉพาะทางนั้น เป็นหนึ่งในช่วงที่เติบโตเร็วที่สุดในอาชีพ
    ผมไม่รู้ C และก็ไม่รู้ Plan 9 มากพอจะใช้ได้อย่างมีประสิทธิภาพ แต่ก็มี ฟีเจอร์ที่เจ๋งและมีประโยชน์ ที่ผมอยากรู้และเรียนรู้เพิ่ม อย่างน้อยก็เพื่อจะได้เสียดายสิ่งที่ไม่มีในสามระบบปฏิบัติการหลักยุคนี้
    ถ้ามีเงิน ผมอยากซื้อเวลาคุยกับทั้งสามคนเพื่อขยายความรู้เรื่อง Go และซื้อเวลาของ rsc กับ rob pike เพื่อทำความเข้าใจ Plan 9 ในแบบที่ผมอยากมีมาตลอดแต่ไม่เคยได้มาด้วยตัวเอง

  • ผมชอบ Plan 9 มาก การเอาหลักการจำนวนมากของมันมาสร้างระบบปฏิบัติการของตัวเองคือ โปรเจกต์วัยเกษียณ และเป้าหมายชีวิตของผม
    แก้ไข: ผมจองชื่อโปรเจกต์นี้ไว้ว่า “chaos10” เพราะคงไม่มีแผนอะไรเหมือน SerenityOS

  • นึกไม่ถึงเลยว่าจะถึงขั้นแพตช์ เคอร์เนล Plan 9 เพื่อให้สิ่งนี้ทำงานได้

    • ทำไมจะไม่ล่ะ? ชัดเจนว่าไม่เคยมีใครลองทำอะไรแบบนี้อย่างจริงจังมาก่อน ดังนั้นปริมาณงานที่ขาดไปก็ดูค่อนข้างน้อย :)