تخطَّ إلى المحتوى

تحليل تقني معمّق

ضبط مكدّس شبكة Linux ضد DDoS: طوابير NIC وRSS/RPS وXDP

آخر تحديث: أغسطس 2026 · طوابير NIC وتوزيع الحزم وربط IRQ وXDP · زمن القراءة ~18 دقيقة

سيل وارد واحد يُقسَّم عند المدخل إلى قنوات متوازية كثيرة، تغذّي كلٌّ منها عاملها الخاص، فلا يُثقَل أي عامل؛ وتُقطع إحدى القنوات مبكراً عند بوابة المدخل.

حين يكون الهجوم معدّل حزم لا عرض نطاق، تبلغ نواة معالج واحدة 100% في softirq بينما تبقى البقية خاملة، ولا يفيد أي sysctl. العلاج هو طبقة المشغّل والمقاطعات: مخازن NIC الحلقية، وRSS/RPS/RFS لتوزيع الحزم على النوى، وربط IRQ، وXDP لإسقاط الحزمة في المشغّل قبل المكدّس. هذا الدليل هو المكمّل لتصليب sysctl من جهة معدّل الحزم.

هذا الدليل هو المكمّل من جهة معدّل الحزم لدليل تصليب خادم Linux. ذلك الدليل يدافع عن حالة الاتصالات بـ sysctl: طوابير SYN، وconntrack، وواصفات الملفات. وهذا يدافع عن مسار معالجة الحزم. عن NIC، وطوابيره، والمقاطعات، ومسار الاستقبال، أي كل ما ينشط حين يُقاس الهجوم بعدد الحزم في الثانية لا بالحالة.

العَرَض الذي يقودك إلى هنا محدّد جداً. نواة معالج واحدة مثبّتة عند نحو 100% في softirq بينما البقية خاملة، وعرض النطاق بعيد جداً عن حدّ الوصلة. فيضان من الحزم الصغيرة قادر على إشباع معالجة الحزم على نواة واحدة قبل أن يملأ الأنبوب بوقت طويل، ولا يمسّ ذلك أيُّ sysctl من الدليل الآخر. كل ضبط أدناه يأتي مع أمر ethtool أو sysfs الخاص به ومع العدّاد الذي يُظهر عمله.

الأعراض، والطبقة التي تخصّها، والأمر
الجهازالعَرَضالطبقةالأمر
نواة واحدة على 100% softirq والبقية خاملةتوزيع RSS / RPS وربط IRQethtool -L; /sys .../rps_cpus; /proc/irq
تزايد عمود softnet 'dropped'مخزن NIC الحلقي؛ netdev backlog/budgetethtool -G; sysctl net.core.netdev_*
تزايد عمود softnet 'squeezed'ميزانية softirq؛ دمج المقاطعاتnetdev_budget; ethtool -C
معدّل حزم عالٍ من نفايات يبلغ المكدّسإسقاط XDP في المشغّل، قبل conntrackip link set ... xdp; برنامج XDP صغير
فقدان محلّية التدفّق بين النوىRFS (receive flow steering)rps_flow_cnt; rps_sock_flow_entries

كل صف يخصّ طبقة المشغّل والمقاطعات، أسفل تصليب sysctl في دليل خادم Linux. العَرَض الذي يقودك إلى هنا هو انشغال المعالج في softirq وعرض النطاق بعيد جداً عن الحدّ. ولا يفيد أيٌّ من هذا حين تمتلئ الوصلة نفسها.

0. القياس الأساسي أولاً: اقرأ أين الحزم وأين المعالج

أهمّ قراءة هي زمن softirq لكل نواة وإحصاءات softnet:

# softirq لكل نواة — هل نواة واحدة ساخنة والبقية خاملة؟
mpstat -P ALL 1 3        # راقب عمود %soft لكل معالج
# أو
watch -n1 "grep . /proc/softirqs | head"

# softnet_stat: العمود1 مُعالَج، العمود2 مُسقَط، العمود3 وقت/ميزانية SQUEEZED (لكل معالج، hex)
cat /proc/net/softnet_stat

# أي IRQ يُطلَق وعلى أي معالج
cat /proc/interrupts | grep -Ei 'eth|ens|enp|mlx|i40e|ixgbe'

# الإسقاطات والأخطاء على مستوى NIC
ethtool -S eth0 | grep -Ei 'drop|miss|error|fifo|rx_no_buffer'

نواة %soft ساخنة واحدة والبقية خاملة هي بصمة معدّل الحزم. والعمود الثاني في softnet_stat (الإسقاطات) والثالث (squeezed) يخبرانك هل القيد في الـ backlog أم في الميزانية. هذه هي القياسات الأساسية التي يُحكَم على كل تغيير أدناه قياساً عليها.

1. مخازن NIC الحلقية: أول موضع تُفقَد فيه الحزم

مخزن الاستقبال الحلقي هو حيث يودع NIC الحزم كي تلتقطها النواة. وتحت فيضان الحزم، مخزن صغير الحجم يُسقط الحزم قبل أن يتمكّن أي توزيع من المساعدة:

# أحجام الحلقة الحالية والقصوى
ethtool -g eth0
# ارفع RX (وTX) نحو الحدّ الأقصى الذي يدعمه NIC
ethtool -G eth0 rx 4096 tx 4096
# تأكّد أن عدّاد الإسقاط توقّف عن التزايد بعد التغيير
ethtool -S eth0 | grep -Ei 'rx_no_buffer|rx_missed|fifo'

الحلقة الأكبر تكلّف قليلاً من الذاكرة والكمون؛ وعلى خادم يتلقّى فيضان حزم، تلك المبادلة مجدية دائماً تقريباً. وإذا استمرّ rx_no_buffer_count في التزايد عند أقصى حجم للحلقة، فقد انتقل القيد إلى المعالج، وذلك موضوع الأقسام التالية.

2. RSS: وزّع معالجة الاستقبال على النوى في العتاد

Receive Side Scaling يوزّع التدفّقات الواردة بالتجزئة على عدة طوابير استقبال في NIC، لكلٍّ منها مقاطعتها الخاصة على نواتها. وهي أكفأ طريقة لمنع نواة واحدة من أن تصير عنق الزجاجة:

# كم قناة combined/استقبال لدى NIC وكم منها مفعّلة؟
ethtool -l eth0
# فعّل من طوابير combined بقدر النوى التي تستطيع تخصيصها لخدمتها
ethtool -L eth0 combined 8

# اعرض جدول توجيه RSS (إلى أي طابور يذهب كل دلو تجزئة)
ethtool -x eth0
# بعد التفعيل ينبغي أن يُظهر /proc/interrupts مقاطعات NIC موزّعة على النوى،
# وأن يُظهر mpstat توزيع %soft بدل نواة ساخنة واحدة
mpstat -P ALL 1 3

RSS هو الخيار الأول، لأن التوزيع يجري في العتاد وبلا كلفة معالج. وحدّه هو عدد الطوابير الذي يوفّره NIC. وحيث تكون قليلة جداً، وهو شائع في بطاقات NIC الافتراضية، يسدّ الثغرة RPS برمجياً.

3. RPS وRFS: توزيع برمجي حيث يقصّر العتاد

Receive Packet Steering يوزّع الحزم على النوى داخل النواة؛ وReceive Flow Steering يضيف محلّية التدفّق فيُنزل تدفّقاً على النواة التي يعمل عليها تطبيقه:

# RPS: اضبط قناع المعالج (قناع بتّي hex للنوى) لطابور استقبال
echo ff > /sys/class/net/eth0/queues/rx-0/rps_cpus

# RFS: أولاً حجم جدول التدفّقات العام، ثم لكل طابور
echo 32768 > /proc/sys/net/core/rps_sock_flow_entries
echo 32768 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt
# تحقّق أن التوزيع انتقل: لا ينبغي لأي نواة أن تحمل كامل عبء softirq الآن
grep NET_RX /proc/softirqs

فعّل RPS لكل طابور استقبال بقناع يستبعد النوى المحجوزة للتطبيق. وRFS فوقه يرسل حزم تدفّق واحد إلى نواة واحدة، ما يساعد محلّية الذاكرة المخبّأة. اضبط rps_sock_flow_entries وrps_flow_cnt لكل طابور معاً.

4. ربط IRQ: ثبّت الطوابير، وفكّر في إيقاف irqbalance

مع وجود طوابير RSS، تثبيت مقاطعة كل طابور على نواة مخصّصة يجعل التوزيع قابلاً للتوقّع، بدل أن يترك irqbalance ينقلها تحت الحمل:

# اعثر على أرقام IRQ لطوابير NIC
grep -Ei 'eth0|ens|enp' /proc/interrupts | awk '{print $1}' | tr -d ':'

# ثبّت IRQ على نواة محدّدة (اكتب قناع النواة hex إلى smp_affinity)
echo 2 > /proc/irq/145/smp_affinity     # النواة 1
echo 4 > /proc/irq/146/smp_affinity     # النواة 2

# على مضيف مخصّص عالي المعدّل، أوقف إعادة خلط irqbalance
systemctl stop irqbalance
systemctl disable irqbalance

إيقاف irqbalance قرار يُتّخذ بالقياس لا قرار عام. على مضيف مخصّص تحت هجوم معدّل حزم، التثبيت اليدوي أكثر قابلية للتوقّع؛ وعلى خادم عام الغرض، irqbalance كافٍ غالباً. احجز النوى الحاملة لمقاطعات NIC، وأبقِ التطبيق بعيداً عنها.

5. ميزانية softirq ودمج المقاطعات

إذا تزايد العمود الثالث في softnet_stat (squeezed)، فإن معالج softirq يبلغ ميزانيته ويتنازل قبل تفريغ الطابور. ارفع الميزانية، واستخدم الدمج لخفض عبء المقاطعات لكل حزمة:

# ارفع كم حزمة وكم زمناً يمكن لمرور softirq واحد أن يعالج
sysctl -w net.core.netdev_budget=60000
sysctl -w net.core.netdev_budget_usecs=8000
sysctl -w net.core.netdev_max_backlog=250000

# دمج المقاطعات: اجمع المقاطعات؛ adaptive يرفع الدمج كلما ارتفع المعدّل
ethtool -C eth0 adaptive-rx on rx-usecs 64
# ينبغي أن يتوقّف عمود squeezed (الثالث في الصف) عن التزايد
awk '{print strtonum("0x"$3)}' /proc/net/softnet_stat

الدمج تحت الفيضان يبادل قليلاً من الكمون بكثير من الكفاءة. وقبل تثبيت rx-usecs عدواني، قِس المسار الحسّاس للكمون في التشغيل العادي.

6. عمليات التفريغ: ما يبقى وما يُوقَف تحت الهجوم

عمليات التفريغ عديمة الحالة (المجموع الاختباري، GRO/GSO/TSO) تفيد عموماً وينبغي أن تبقى مفعّلة. الوحيدة التي تستحق التدقيق هي LRO، لأنها تدمج الحزم بصورة قد تعيق التوجيه وبعض الفحص:

# اعرض حالة التفريغ
ethtool -k eth0 | grep -Ei 'gro|gso|tso|lro|rx-checksum'
# Generic Receive Offload يفيد عادةً؛ أبقِه مفعّلاً
ethtool -K eth0 gro on
# أوقف LRO إذا كان المضيف يوجّه/يجسّر أو تحتاج رؤية لكل حزمة
ethtool -K eth0 lro off

7. XDP: أسقِط في المشغّل، قبل المكدّس

لفيضان بمعدّل حزم يعجز التوزيع عن تبديده، فإن XDP هو أداة المضيف الوحيدة التي تغيّر رتبة المقدار. يشغّل برنامجاً صغيراً في المشغّل، قبل أن تدخل الحزمة مكدّس الشبكة. قبل conntrack، وقبل nftables، وقبل تخصيص الذاكرة. وقادر على إسقاط ملايين الحزم في الثانية بجزء يسير من المعالج الذي يكلّفه الإسقاط نفسه لاحقاً:

# اربط برنامج XDP مُصرَّفاً (يُسقط وفق المعيار الذي ينفّذه)
ip link set dev eth0 xdp obj xdp_drop.o sec xdp

# تأكّد أنه مربوط وفي أي وضع (native الأفضل؛ generic هو الاحتياطي)
ip link show eth0 | grep -o 'xdp[a-z]*'

# افصل
ip link set dev eth0 xdp off

XDP الأصلي يتطلّب دعم المشغّل؛ ودونه يعمل البرنامج في وضع generic بفائدة أقل. وXDP أكثر جهداً من بقية الأقسام وليس أول ما يُلجأ إليه. لكن حين يكون الهجوم عدد الحزم في الثانية والتوزيع قد نفد، فالإسقاط في المشغّل هو ما يفعله جهاز مخصّص في العتاد، منفَّذاً برمجياً على حافة المضيف.

الإشارات التي تُربَط بالمراقبة

# 1. softirq لكل نواة — بصمة النواة الساخنة
mpstat -P ALL 1 1 | awk '/%soft|Average/{print}'
# 2. إسقاطات softnet وحالات squeezed
awk '{d+=strtonum("0x"$2); s+=strtonum("0x"$3)} END{print "dropped",d,"squeezed",s}' /proc/net/softnet_stat
# 3. الإسقاطات على مستوى NIC
ethtool -S eth0 | grep -Ei 'rx_no_buffer|rx_missed|drop'
# 4. إجمالي معدّل المقاطعات
grep NET_RX /proc/softirqs

نواة ساخنة واحدة مع عدّاد squeezed متزايد هي بصمة معدّل الحزم؛ وتزايد إسقاطات NIC عند مخزن حلقي مرفوع إلى أقصاه يعني أن عنق الزجاجة هو المعالج لا الحلقة، وأن الخطوة التالية توزيع أو XDP.

الحدّ الصادق لهذه الطبقة

هذه الطبقة تدافع عن معدّل الحزم؛ أي عدد الحزم في الثانية الذي يُشبع المعالج، وقد يضرب بعيداً جداً عن حدّ عرض النطاق. حالتان تقعان خارجها.

الأولى عرض النطاق. إذا ملأ الهجوم وصلة الوصول، فالحزم تُسقط في الأعلى قبل أن يراها NIC، ولا يعمل أي طابور أو توزيع أو XDP.

أين تتوقف الطبقة داخل المنشأة عن أن تنفع وصلة الوصول لديك: 10 غيغابت/ث الخط مُشبع أصلاً — الطبقة العليا فقط الجهاز داخل المنشأة يخفّف 2 غيغابت/ث 8 غيغابت/ث 25 غيغابت/ث 120 غيغابت/ث 1 تيرابت/ث+ حجم الهجوم (مقياس لوغاريتمي)
أسفل الوصلة لطبقة معالجة الحزم نصيب؛ وفوقها لا تصل الحزم أصلاً كي تُوزَّع أو تُسقَط.

والثانية استنزاف الحالة، وهو موضوع الدليل الآخر: جداول الاتصالات والطوابير، لا معالجة الحزم. والدليلان معاً يغطّيان المضيف. هذا يُبقي المعالج قادراً على معالجة الحزم، ودليل تصليب الخادم يمنع امتلاء حالة الاتصالات. وفوق الوصلة، الجواب في طبقة الشبكة، حيث يُنفَّذ الإسقاط نفسه الذي يفعله هذا الدليل في XDP، في العتاد وعلى نطاق واسع.

ترتيب التطبيق

  1. أكّد العَرَض (القسم 0): نواة softirq ساخنة واحدة، وعرض النطاق أدنى بكثير من الحدّ.
  2. ارفع مخازن NIC الحلقية؛ وتأكّد من توقّف إسقاطات NIC.
  3. فعّل RSS بعدد من الطوابير يستطيع النوى خدمته؛ وتحقّق من التوزيع.
  4. أضف RPS/RFS حيث تكون طوابير العتاد قليلة جداً.
  5. ثبّت ربط IRQ؛ وقرّر أمر irqbalance بالقياس.
  6. ارفع ميزانية softirq وفعّل الدمج المتكيّف إن استمرّت حالات squeezed.
  7. لفيضان يعجز التوزيع عن تبديده، انشر برنامج إسقاط XDP.
  8. اربط الإشارات الأربع بالمراقبة.

الخطوتان الثالثة والرابعة تحلّان معظم مشكلات معدّل الحزم بتوزيع الحمل؛ وXDP في الخطوة السابعة تصعيد لما يعجز التوزيع وحده عن استيعابه.

أسئلة متكررة

كيف أعرف أنني أحتاج هذه الطبقة لا ضبط sysctl؟
من العَرَض. إذا كانت نواة معالج واحدة مثبّتة عند نحو 100% في زمن المقاطعات البرمجية (softirq) بينما البقية خاملة، وكان إجمالي عرض النطاق بعيداً جداً عن حدّ الوصلة، فأنت مقيَّد بمعدّل الحزم، وهذه هي الطبقة التي تُضبط. أمّا إذا كانت جداول الاتصالات أو الطوابير أو واصفات الملفات تمتلئ والمعالج بخير، فتلك استنزاف حالة وتخصّ تصليب sysctl في دليل خادم Linux. والطبقتان يكمّل بعضهما بعضاً: sysctl يدافع عن حالة الاتصالات، وهذه تدافع عن مسار معالجة الحزم.
RSS وRPS وRFS: ما الفرق؟
توزّع معالجة الحزم على النوى بمستويات مختلفة. RSS (Receive Side Scaling) يجري في عتاد NIC ويوزّع التدفّقات بالتجزئة على عدة طوابير استقبال، لكلٍّ منها مقاطعتها الخاصة. وهو الأكفأ والخيار الأول حين يدعم NIC طوابير كافية. وRPS (Receive Packet Steering) هو المكافئ البرمجي، يوزّع داخل النواة حين لا يتوفّر RSS العتادي أو تكون طوابيره قليلة. وRFS (Receive Flow Steering) يضيف فوق RPS محلّية التدفّق، فيوجّه التدفّق إلى النواة التي يعمل عليها تطبيقه، ما يحسّن سلوك الذاكرة المخبّأة. استخدم RSS حيث تستطيع، وRPS حيث لا تستطيع، وRFS مع RPS على المضيفات متعدّدة النوى.
هل يستحق XDP العناء في مواجهة DDoS أم أنه مبالغة؟
لهجمات معدّل الحزم العالي هو أكثر دفاع فعّالية على مستوى المضيف، لأنه يُسقط الحزم في المشغّل قبل أن تدخل مكدّس الشبكة. قبل conntrack، وقبل iptables/nftables، وقبل أي تخصيص للذاكرة. وبرنامج XDP صغير يُسقط وفق معيار بسيط (مجموعة مصادر، أو فحص حزمة تالفة، أو منفذ) قادر على إسقاط ملايين الحزم في الثانية بجزء يسير من المعالج الذي يكلّفه الإسقاط نفسه في nftables. نشره أكثر جهداً ويتطلّب مشغّلاً بدعم XDP الأصلي للفائدة الكاملة، فليس أول ما يُلجأ إليه. لكن لفيضان بمعدّل حزم يعجز التوزيع عن تبديده، فهو أداة المضيف الوحيدة التي تغيّر رتبة المقدار.
هل يفيد دمج المقاطعات تحت الهجوم أم يضرّ؟
يبادل الكمون بالكفاءة، وتحت فيضان الحزم يغلب جانب الكفاءة عادةً. الدمج يجمّع المقاطعات كي لا يُقاطَع المعالج عند كل حزمة؛ والدمج المتكيّف (adaptive-rx) يرفع التجميع كلما ارتفع المعدّل. وهذا يقلّل عبء المقاطعات في اللحظة التي يكون فيها معدّل الحزم هو المشكلة. وثمنه كمون مضاف يسير، وهو مهمّ للأحمال الحسّاسة للكمون في التشغيل العادي. لذا فالنهج الصادق أن تقيس الحالتين لا أن ترفع الدمج بعشوائية.
هل أوقف irqbalance وأربط يدوياً؟
غالباً نعم، على خادم تحت هجوم معدّل حزم. irqbalance ينقل المقاطعات ديناميكياً؛ وهذا جيد عموماً لكنه قد يفسد ربط طوابير RSS بالنوى المضبوط بعناية ويقفز بتدفّق بين النوى تحت الحمل. ولمضيف مخصّص عالي الإنتاجية أو تحت هجوم، فربط مقاطعة كل طابور استقبال في NIC بنواة محدّدة، وإبقاء تلك النوى بعيدة عن التطبيق، أكثر قابلية للتوقّع. أمّا على خادم عام الغرض فإبقاء irqbalance مفعّلاً صحيح غالباً. وهو قرار يُتّخذ بالقياس لا تشغيلاً/إيقافاً عاماً.
هل توقف هذه الإعدادات هجوماً حجمياً (بعرض النطاق)؟
لا. إذا ملأ الهجوم وصلة الوصول، فالحزم تُسقط في الأعلى قبل أن يراها NIC، ولا يعمل أي طابور أو توزيع أو XDP. هذه الطبقة تدافع عن معدّل الحزم؛ أي عدد الحزم في الثانية الذي يُشبع المعالج، وقد يحدث بحزم صغيرة بعيداً جداً عن حدّ عرض النطاق. أمّا عرض النطاق فوق الوصلة فمسألة طبقة الشبكة ولا يُحلّ على المضيف.

النشر: أغسطس 2026

يُحدَّث هذا الدليل كلما طرح المصنّعون طرازات وشروط ترخيص جديدة. كيف نقارن بين المصنّعين