پشتیبانی چندسکویی tokio-tun و offload در Linux در مسیر نسخهٔ 1.0

چرا مهم است

اگر با Rust روی TUN/TAP کار می‌کنی، تفاوت پشتیبانی سیستم‌ها برایت مهم است: موبایل فقط I/O دارد و offload مختص Linux است. برای استفاده از offload هم باید header و اندازهٔ buffer را در برنامه لحاظ کنی.

قبل از خواندن، این‌ها را بدان۳ مفهوم
TUN

نوعی interface مجازی شبکه در layer 3 که به برنامه اجازه می‌دهد packet‌های IP را بخواند و بنویسد.

در حال نگارش

file descriptor

شناسه‌ای که سیستم‌عامل برای دسترسی یک process به منبع بازشده‌ای مثل فایل، socket یا device در اختیار آن می‌گذارد.

در حال نگارش

offload

واگذاری بخشی از پردازش به بخش دیگری از سیستم؛ در شبکه می‌تواند شامل پردازش checksum یا segmentation باشد.

در حال نگارش

پروژهٔ tokio-tun برای کار asynchronous با TUN/TAP در Rust و با استفاده از Tokio،؜ پشتیبانی از FreeBSD،؜ macOS،؜ iOS و Android را در کنار Linux معرفی کرده است. در همهٔ platform‌های پشتیبانی‌شده، packet I/O از طریق AsyncFd به Tokio متصل می‌شود؛ این crate از polling loop اختصاصی یا blocking fallback استفاده نمی‌کند.

دامنهٔ پشتیبانی در هر سیستم متفاوت است. Linux از TUN،؜ TAP،؜ multi-queue و offload پشتیبانی می‌کند. FreeBSD هر دو نوع TUN و TAP را دارد، اما multi-queue و offload در آن در دسترس نیست. macOS از driver داخلی utun استفاده می‌کند و فقط TUN در layer 3 را ارائه می‌دهد؛ ساخت utun نیز به دسترسی root نیاز دارد. تنظیم MAC address برای TAP در Linux و FreeBSD ممکن است، اما TUN اساساً MAC address ندارد.

پشتیبانی Android و iOS فقط به I/O محدود است. برنامه باید یک file descriptor آماده را از بیرون به TunQueue بدهد؛ tokio-tun در این دو سیستم device نمی‌سازد و مستقیماً با VpnService یا NEPacketTunnelFlow یکپارچه نمی‌شود. در Android،؜ file descriptor از VpnService می‌آید و در iOS به یک NetworkExtension bridge نیاز است. در هر دو حالت، bridge باید packet خام IP فراهم کند.

در Linux،؜ فراخوانی TunBuilder::offload() قابلیت‌های checksum،؜ TSO4،؜ TSO6 و GRO مبتنی بر NAPI را همراه با virtio-net header فعال می‌کند. هر packet دریافتی با یک header ده‌بایتی شروع می‌شود و packet ارسالی هم باید آن را داشته باشد. این حالت با packet_info() قابل ترکیب نیست. نکتهٔ مهم این است که GRO فقط برای packet‌های نوشته‌شده از userspace به kernel اعمال می‌شود، نه packet‌های تحویلی به userspace؛ مسئولیت منطق segmentation و coalescing همچنان با برنامه است. همچنین receive buffer باید دست‌کم VIRTIO_NET_HDR_LEN + 65_536 بایت باشد، چون packet‌های GSO می‌توانند از MTU بزرگ‌تر باشند.

برای انتقال queue میان process‌ها، می‌توان Tun را به TunQueue و سپس به OwnedFd تبدیل کرد. این تبدیل دسترسی به accessor‌های interface را حذف می‌کند؛ بنابراین اطلاعاتی مثل نام interface باید پیش از آن نگه داشته شوند. TunQueue::new نیز file descriptor را non-blocking می‌کند؛ تغییری که به‌دلیل اشتراک open file description،؜ در process فرستنده هم اثر دارد.

نکته کلیدی

پیش از انتقال برنامه بین سیستم‌ها، قابلیت‌های موردنیازت را با محدودیت‌های هرکدام تطبیق بده. در Linux هم offload را صرفاً یک گزینهٔ فعال‌سازی نبین؛ header لازم است و منطق segmentation و coalescing همچنان بر عهدهٔ برنامه می‌ماند.

خواندن مقاله اصلی (در زبانه‌ی جدید باز می‌شود)
برچسب‌ها (۴)