درگاه‌های ارتباطی پرظرفیت VPN که همزمان به هزاران تونل رمزنگاری‌شده کاربردی پاسخ می‌دهند، نیازمند توان عملیاتی متقارن و پایداری در مسیرهای ورود و خروج بسته‌ها هستند. در حالی که راهکارهای شتاب‌بخشی ورودی مانند RSS و RPS ترافیک دریافتی را به خوبی بین هسته‌های پردازنده توزیع می‌نمایند، مسیر ارسال خروجی (egress) زیر بار سنگین اغلب با افت کارایی غیرمنتظره‌ای مواجه می‌گردد.

روی سرورهای چندهسته‌ای نوین که مجهز به کارت‌های شبکه با سرعت‌های ۱۰، ۲۵ یا ۱۰۰ گیگابیت بر ثانیه با قابلیت پشتیبانی از چند صف سخت‌افزاری (Multi-Queue) هستند، پردازش بسته‌های خروجی مستعد رقابت بر سر قفل‌های هسته لینوکس (lock contention) است. هنگامی که چندین هسته پردازنده به طور همزمان تلاش می‌کنند ترافیک خروجی را وارد یک صف فیزیکی واحد نمایند، قفل‌های چرخشی (spinlock) فرآیند پردازش را به صورت متوالی و کند درمی‌آورند. این رویداد سبب اتلاف چرخه‌های پردازنده، پراکندگی خطوط کش L1/L2/L3 میان سوکت‌های پردازنده و جهش ناگهانی تاخیر انتهای توزیع (p99) می‌شود.

قابلیت Transmit Packet Steering (XPS) لینوکس در پشته شبکه هسته این تنگنا را مرتفع می‌سازد. با ایجاد یک نگاشت هوشمند و قطعی میان هسته‌های پردازنده (یا صف‌های دریافت) و صف‌های ارسال فیزیکی کارت شبکه، XPS سربار قفل‌های صف را رفع کرده و بازدهی زیرسیستم حافظه را در درگاه‌های لبه شبکه ارتقا می‌دهد.


Tx Lock Contention: گلوگاه مسیر ارسال در معماری‌های چندهسته‌ای

برای درک علل افت کارایی در ارسال داده، مسیر بسته‌های خروجی را در ساختار چندصفی شبکه لینوکس مرور می‌کنیم:

  1. تولید یا بازفروارد بسته: برنامه‌ها، رابط‌های تونل (نظیر wg0 در WireGuard) یا لایه‌های هدایت داده، ساختار بافر سوکت (sk_buff) را آماده می‌سازند.
  2. گزینش صف ارسال: پشته شبکه تابع dev_pick_tx() را در فایل net/core/dev.c فراخوانی می‌کند تا صف سخت‌افزاری مقصد (struct netdev_queue) مشخص شود.
  3. تصاحب قفل صف: هسته لینوکس پیش از ثبت بسته در بافر حلقوی درایور از طریق ndo_start_xmit()، باید قفل انحصاری آن صف را در اختیار بگیرد: __netif_tx_lock().
تداخل صف‌ها در نبود XPS (رقابت چندین هسته بر سر یک صف فیزیکی):

هسته ۰ ──► [ dev_queue_xmit() ] ──┐
                                  ├──► [ قفل چرخشی __netif_tx_lock() ] ──► [ صف ارسال ۰ ]
هسته ۱ ──► [ dev_queue_xmit() ] ──┤    (اتلاف پردازش و قفل‌های مداوم)
                                  │
هسته ۲ ──► [ dev_queue_xmit() ] ──┘

در حالت پیش‌فرض و بدون فعال‌سازی نگاشت، انتخاب صف متکی بر درهم‌سازی جریان‌ها (skb_tx_hash()) است. در محیط‌های پرترافیک VPN که هزاران ارتباط از ویژگی‌های کپسوله‌سازی UDP مشابهی بهره می‌برند، هسته‌های مختلف ناگزیر بسته‌ها را در لحظاتی یکسان به یک صف مشترک هدایت می‌کنند.

با برخورد چندین هسته به قفل __netif_tx_lock()، رشته‌های پردازشی وارد حلقه‌های اتلاف وقت (busy-wait) می‌شوند. با افزایش تعداد هسته‌ها به ۳۲، ۶۴ یا ۱۲۸، زمان اتلاف قفل به شکل نمایی بالا می‌رود. ابزارهای پایش مانند perf top نشان می‌دهند بخش عمده‌ای از توان پردازنده به جای اجرای الگوریتم‌های رمزنگاری در تابع queued_spin_lock_slowpath به هدر می‌رود.


Architectural Mechanics: نحوه کارکرد پروتکل Linux XPS

فناوری Transmit Packet Steering یک لایه نگاشت انعطاف‌پذیر میان زمینه‌های پردازش CPU و صف‌های ارسال فیزیکی کارت شبکه پدید می‌آورد. این فناوری دارای دو شیوه هدایت پایه است: نگاشت بر مبنای هسته‌های پردازنده و نگاشت بر مبنای صف‌های دریافت.

1. هدایت بر پایه هسته‌های پردازنده (xps_cpus)

در این شیوه، هر هسته پردازشی به صف‌های فیزیکی مشخصی اختصاص داده می‌شود. در ساختار فایل‌های sysfs برای هر صف ارسال، فایلی به نام xps_cpus برای تعیین ماسک بیتی وجود دارد. پس از تنظیم:

  • هر هسته پردازنده بسته‌ها را منحصراً از طریق صف سخت‌افزاری تعیین‌شده برای خود منتقل می‌کند.
  • اگر تعداد صف‌های سخت‌افزاری ارسال برابر یا بیشتر از هسته‌های فعال باشد، هر هسته یک مسیر اختصاصی و فارغ از رقابت در اختیار خواهد داشت.
  • به دلیل دسترسی همزمان تنها یک هسته به ساختار netdev_queue مشخص، فراخوانی __netif_tx_lock() بدون درنگ و بدون انتظار انجام می‌پذیرد.
ارسال بدون قفل با نگاشت مبتنی بر هسته در XPS (تخصیص ۱ به ۱):

هسته ۰  ──► [ xps_cpus = 0x1 ] ──► [ صف ارسال اختصاصی ۰ ] ──► [ درگاه شبکه ]
هسته ۱  ──► [ xps_cpus = 0x2 ] ──► [ صف ارسال اختصاصی ۱ ] ──► [ درگاه شبکه ]
هسته ۲  ──► [ xps_cpus = 0x4 ] ──► [ صف ارسال اختصاصی ۲ ] ──► [ درگاه شبکه ]
هسته ۳  ──► [ xps_cpus = 0x8 ] ──► [ صف ارسال اختصاصی ۳ ] ──► [ درگاه شبکه ]

2. هدایت بر پایه صف‌های دریافت (xps_rxqs)

کارت‌های شبکه و زیرساخت‌های VPN معمولاً جریان‌های متقارن دوطرفه را پردازش می‌کنند. هنگامی که یک درگاه بسته‌ای را از صف ورودی Rx شماره $N$ دریافت می‌کند، هسته پردازنده اطلاعات بسته و جدول‌های مسیریابی را در کش L1/L2 محلی خود به صورت گرم نگه‌داشته است.

پیکربندی xps_rxqs صف ارسال را با شماره صف ورودی متناظر می‌سازد:

  • بسته‌ای که از صف Rx شماره ۰ دریافت شده، بسته‌های پاسخ خود (نظیر تاییدیه‌های TCP ACK یا پاسخ تبادل کلید) را از طریق صف Tx شماره ۰ بازمی‌فرستد.
  • این تقارن تضمین می‌کند که عملیات خروج توسط همان هسته‌ای که بسته را تحویل گرفته هدایت شود و مانع از نامعتبر شدن حافظه کش میان هسته‌ها می‌گردد.

NUMA Topology and Cache Locality: پایداری حافظه در درگاه‌های پرترافیک

در سرورهای سازمانی مجهز به چند سوکت پردازنده (مانند پلتفرم‌های دوسوکته AMD EPYC یا Intel Xeon)، معماری حافظه غیریکنواخت (NUMA) نقشی بنیادین در پایداری سرعت شبکه ایفا می‌کند.

پرش‌های ناخواسته داده و فشار بر خطوط ارتباطی پردازنده‌ها

کارت‌های شبکه PCIe مستقیماً به ریشه سخت‌افزاری یک سوکت NUMA ویژه متصل هستند. چنانچه هسته‌ای در گره NUMA 1 بسته‌ای را بدون نگاشت آگاه از NUMA از طریق کارت شبکه‌ای متعلق به گره NUMA 0 مخابره نماید:

  1. اشباع گذرگاه ارتباطی: هسته ناچار است آدرس‌های DMA و دستورات را از طریق گذرگاه میان دو سوکت (مانند AMD Infinity Fabric یا Intel UPI) جابه‌جا کند.
  2. تداخل خطوط کش L3: قفل __netif_tx_lock() و شاخص‌های حافظه حلقوی پیوسته میان حافظه کش L3 دو سوکت فیزیکی دست‌به‌دست می‌شوند.
  3. افزایش تاخیرهای نوسانی: دسترسی به حافظه سوکت راه دور چرخه زمانی بسیار طولانی‌تری نسبت به حافظه محلی می‌طلبد و موجب نوسان تاخیر می‌گردد.

تنظیم ماسک‌های بیتی XPS در چارچوب مرزهای محلی هر نود NUMA اطمینان می‌دهد که پردازنده‌ها صرفاً صف‌های کارت شبکه متصل به همان سوکت را به کار گیرند.


پیکربندی هسته: فعال‌سازی و تنظیم پارامترهای XPS در لینوکس

پیاده‌سازی بهینه XPS مستلزم بررسی ظرفیت صف‌های کارت شبکه، محاسبه دقیق ماسک‌های بیتی پردازنده و هماهنگی با مدیریت صف درایور است.

1. تنظیم ماسک‌های بیتی اتصال هسته‌ها به صف‌های ارسال

به عنوان نمونه، برای ایجاد نگاشت یک‌به‌یک میان ۴ هسته و ۴ صف در رابط شبکه eth0:

# مشاهده صف‌های فیزیکی ارسال در کارت شبکه eth0
ls -d /sys/class/net/eth0/queues/tx-*

# تخصیص هسته ۰ (ماسک 0x1) به صف خروجی Tx-0
echo "1" | sudo tee /sys/class/net/eth0/queues/tx-0/xps_cpus

# تخصیص هسته ۱ (ماسک 0x2) به صف خروجی Tx-1
echo "2" | sudo tee /sys/class/net/eth0/queues/tx-1/xps_cpus

# تخصیص هسته ۲ (ماسک 0x4) به صف خروجی Tx-2
echo "4" | sudo tee /sys/class/net/eth0/queues/tx-2/xps_cpus

# تخصیص هسته ۳ (ماسک 0x8) به صف خروجی Tx-3
echo "8" | sudo tee /sys/class/net/eth0/queues/tx-3/xps_cpus

در سرورهایی که شمار هسته‌ها از تعداد صف‌های ارسال فراتر می‌رود، هسته‌هایی که دارای کش فیزیکی L3 مشترک هستند باید در قالب یک ماسک بیتی بر روی یک صف قرار گیرند.

2. هم‌افزایی قابلیت XPS با ابزار Byte Queue Limits (BQL)

اگرچه XPS رقابت قفل‌ها را حذف می‌کند، اندازه بافر فیزیکی نیز باید مهار گردد تا پدیده تراکم بیش از حد بافر (bufferbloat) رخ ندهد. ابزار Byte Queue Limits (BQL) در سطح صف‌های درایور به صورت پویا عمل می‌کند:

# بررسی سقف ظرفیت محاسبه‌شده توسط BQL روی صف Tx شماره ۰
cat /sys/class/net/eth0/queues/tx-0/byte_queue_limits/limit

# مشاهده حجم بایت‌های در صف پردازش کارت شبکه
cat /sys/class/net/eth0/queues/tx-0/byte_queue_limits/inflight

ترکیب XPS و BQL ساختار بهینه‌ای می‌سازد: XPS ثبت آنی بسته‌ها در صف را ممکن کرده و BQL با تنظیم حجم صف سخت‌افزاری، تاخیر بسته‌ها را در سطح حداقل تثبیت می‌کند.


بررسی معماری: مقایسه ارسال پیش‌فرض و استفاده از قابلیت XPS

جدول زیر نتایج ارزیابی عملکرد روی یک مسیریاب لبه شبکه 40GbE را تحت بار سنگین بسته‌های ۶۴ تا ۱۴۲۰ بایتی نمایش می‌دهد:

شاخص ارزیابی روش توزیع پیش‌فرض صف پیکربندی متقارن XPS دستاورد ساختاری
رقابت بر سر قفل (__netif_tx_lock) ۱۸ تا ۳۲ درصد زمان پردازنده کمتر از ۰.۲ درصد پردازنده آزادسازی حدود ۳۰٪ توان هسته‌ها
نرخ خطای دسترسی به کش L3 ۱۴.۸ خطا در هر هزار بسته ۲.۱ خطا در هر هزار بسته ارتقای ۷ برابری دسترس‌پذیری کش
بار خطوط ارتباطی UPI/IF بالا (جابه‌جایی مدام داده‌ها) متمرکز در نود NUMA محلی کاهش چشمگیر بار ترافیک گذرگاه
تاخیر انتهای توزیع در صدک ۹۹ ۴.۸ میلی‌ثانیه زیر بار زیاد ۰.۶۵ میلی‌ثانیه زیر بار زیاد کاهش ۸۶ درصدی تغییرات تاخیر
توان هدایت بسته‌ها (Mpps) ۸.۲ میلیون بسته بر ثانیه ۱۴.۱ میلیون بسته بر ثانیه رشد ۷۲ درصدی توان عملیاتی
به هم ریختن ترتیب ارسال رخداد مقطعی در پی قفل‌ها توالی کاملاً منظم روی هر هسته پیشگیری از ارسال مجدد بسته‌های TCP

معماری RiceGuard: بهینه‌سازی مسیر ارسال بدون قفل

در زیرساخت اختصاصی VPNRice، سرورهای لبه شبکه RiceGuard ماژول‌های پردازش چندرشته‌ای را برای استفاده کامل از اتصالات چندگیگابیتی به کار می‌گیرند. هر پردازشگر رمزنگاری به واسطه قابلیت اتصال اختصاصی پردازنده (CPU Pinning) بر روی یک هسته پایدار نگه داشته می‌شود.

لایه ارسال ترافیک RiceGuard این چینش را مستقیماً با جدول‌های XPS هسته لینوکس هماهنگ می‌سازد:

/* راه‌اندازی وابستگی پردازشی و ارسال داده در RiceGuard */
int configure_worker_egress_affinity(int worker_id, int core_id) {
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(core_id, &cpuset);

    /* تثبیت فرآیند پردازشی روی هسته مشخص شده */
    if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) != 0) {
        perror("pthread_setaffinity_np");
        return -1;
    }

    /* سوکت خروجی بسته‌ها را مستقیماً به صف XPS مرتبط تحویل می‌دهد */
    return 0;
}

با تمرکز خروجی بسته‌های رمزنگاری‌شده WireGuard بر روی همان هسته‌ای که صف اختصاصی XPS دارد، بسته‌ها بدون نیاز به توقف پشت قفل‌های متداول به بافر کارت شبکه هدایت می‌شوند.

بهره‌گیری از این چیدمان در کنار بافرهای حلقوی بدون کپی (zero-copy)، پایداری تاخیر زیر یک میلی‌ثانیه‌ای را در تونل‌های ارتباطی VPNRice حتی در پربارترین ساعات شبکه تضمین می‌نماید.