SSD Nodes Learn Hosting plans →
الأدلة Matt Connorبقلم Matt Connor · آخر تحديث في 2026-10-21

كيف تتحقق من AES-NI وتستعيده على VPS؟

تحقق من ظهور AES-NI على VPS، وقِس كلفة إخفاء CPUID على أداء AES-GCM، ثم أعد تفعيل التعليمات عبر OPENSSL_ia32cap.

ما الذي يقدمه AES-NI فعلياً على VPS

AES-NI هو مجموعة من ستة تعليمات x86 تنفّذ جولة واحدة من AES (معيار التشفير المتقدم) في العتاد. إذا أخفى طراز CPU الذي يقدمه مزوّد الخدمة هذه التعليمات، فستظل موجودة في الشريحة نفسها، لكن OpenSSL لن يتمكن من رؤيتها، وسينتقل إلى تنفيذ برمجي يستهلك نحو عشرة أضعاف عدد الدورات لكل بايت. يمكنك التحقق من توفر الميزة باستخدام أمر واحد، وقياس الفارق باستخدام أمرين، وغالباً إعادة تفعيل المسار السريع عبر متغير بيئة واحد.

التعليمات هي AESENC وAESENCLAST وAESDEC وAESDECLAST وAESIMC وAESKEYGENASSIST. أطلقت Intel هذه التعليمات في 2010، ثم لحقتها AMD، لذلك تحتوي شريحة CPU في أي خادم يُرجح أن تستأجره على هذه التعليمات. وتنفّذ التعليمات المرافقة PCLMULQDQ عملية ضرب دون حمل، وهي العملية التي يحتاج إليها GCM (وضع Galois/counter) لإنشاء وسم المصادقة. لا يكون AES-GCM سريعاً إلا عند توفر التعليماتين معاً، لأن التشفير وإنشاء الوسم عمليتان منفصلتان.

تظهر هذه الميزة في أربعة مواضع على VPS ويمكنك ملاحظتها في المراقبة:

  • إنهاء TLS (أمان طبقة النقل). يقضي خادم الويب الذي يقدّم AES-128-GCM أو AES-256-GCM معظم وقت التشفير الكتلي داخل AES.
  • وحدات التخزين المشفّرة. يشغّل LUKS (إعداد المفتاح الموحّد لنظام Linux) وdm-crypt aes-xts مع كل عملية قراءة وكتابة، داخل kernel وعلى CPU.
  • حركة VPN المعتمدة على AES. يعتمد OpenVPN مع AES-256-GCM وIPsec مع AES-GCM عليهما بدرجة كبيرة.
  • النسخ الاحتياطية المشفّرة. أي برنامج يشفّر تدفقاً باستخدام AES قبل خروجه من الخادم يتحمل التكلفة نفسها.

لا يتأثر أحد أحمال العمل الشائعة بهذه الميزة إطلاقاً. يستخدم WireGuard ‏ChaCha20-Poly1305 لبياناته ولا يستخدم AES مطلقاً، لذلك يعمل VPN WireGuard المستضاف ذاتياً بالسرعة نفسها على مضيف يخفي هذا العلم. ويوفر هذا الاختلاف سبباً عملياً للموازنة بين WireGuard وOpenVPN قبل اختيار نفق لـVPS منخفض التكلفة.

كيفية التحقق من أن VPS لديك يدعم AES-NI

ينسخ kernel بتات ميزات CPUID إلى /proc/cpuinfo، لذلك يكفي أمر grep واحد للإجابة عن السؤال.

grep -m1 -o '\baes\b' /proc/cpuinfo
lscpu | grep -i -o '\baes\b'

يعني ظهور aes في ناتج أي من الأمرين أن وحدة المعالجة المركزية تعلن دعم AES-NI لهذا الضيف. ويعني عدم ظهور أي ناتج أنها لا تدعمه. يقرأ lscpu العلامات نفسها، لذلك تتطابق النتيجتان دائماً. استخدم الأمر المثبّت لديك.

تحقق الآن من وحدة المعالجة المركزية التي يذكرها المضيف على أنك تعمل عليها.

grep -m1 'model name' /proc/cpuinfo

يعني ظهور اسم طراز حقيقي مثل Intel(R) Xeon(R) Gold 6338 CPU @ 2.00GHz أو AMD EPYC 7443P 24-Core Processor أن المضيف يمرّر طراز وحدة المعالجة المركزية الفعلية إليك. أما QEMU Virtual CPU version 2.5+ أو Common KVM processor فيعني أن شيئاً آخر يحدث، وهذه هي الحالة التي تستحق الفهم.

لماذا تكون العلامة مفقودة رغم أن المعالج يدعمها

‏CPUID هي التعليمة التي يستخدمها البرنامج لطلب معلومات عن الميزات التي يدعمها المعالج. داخل الآلة الافتراضية، تؤدي CPUID دائماً إلى اعتراض من hypervisor، لذلك يحدد hypervisor ما يُبلَّغ به الضيف. تعرض معظم لوحات التحكم هذا القرار على شكل نموذج CPU للضيف. يُعد qemu64 وkvm64 نموذجي خط أساس عامين، ولا يتضمن أي منهما AES-NI أو SSSE3 ضمن مجموعة الميزات، لذلك لا يرى الضيف علامة aes حتى عندما يكون المضيف الفعلي بمعالج EPYC حديث. إن VPS ضيف على عتاد يملكه طرف آخر، لذلك فإن كل ميزة يبلّغ عنها هي قرار اتُّخذ في مستوى أعلى. إذا كان هذا الفصل بين الطبقات جديداً عليك، فابدأ بقراءة ما هو VPS.

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

يكمن الإصلاح من المصدر في إعداد على المضيف: -cpu host وفق مصطلحات QEMU، أو نموذج مسمّى يتضمن AES-NI، أو +aes صريحة تُضاف إلى النموذج. لا يمكنك ضبط أي من ذلك من داخل الضيف. إن فتح تذكرة دعم، أو اختيار خطة يمرر hypervisor فيها نموذج CPU إلى الضيف، هو الحل المستدام.

قِس الفارق باستخدام openssl speed

لا تعتمد على معيار منشور من دون تحقق. شغّل خوارزمية التشفير التي يتفاوض عليها خادمك فعلياً.

openssl version
openssl speed -evp aes-128-gcm

يُسمّى صف النتيجة AES-128-GCM، ويعرض معدل النقل عند ستة أحجام للكتل، بوحدة 1000 بايت في الثانية. اقرأ عمود 8192 بايت لنقل البيانات بكميات كبيرة، لأن عمود 16 بايت يتأثر أساساً بالنفقات العامة لكل استدعاء، ولا يخبرك بشيء عن تنزيل ملف.

شغّل الأمر نفسه الآن مع تعطيل AES-NI وPCLMULQDQ برمجياً:

OPENSSL_ia32cap="~0x200000200000000" openssl speed -evp aes-128-gcm

تأتي هذه القيمة من توثيق متجه القدرات الخاص بـOpenSSL. تعني ~ في البداية «مسح هذه البتات». البت 57 هو AES-NI، والبت 33 هو PCLMULQDQ، لذلك يحدد 0x200000200000000 هذين الاثنين فقط ولا يحدد غيرهما. إذا كانت القيمة الثانية أقل بكثير من الأولى، فهذا يعني أن AES-NI يعمل على جهازك، وأنك انتهيت. أما إذا تطابقت القيمتان، فهذا يعني أن OpenSSL كان يستخدم مسار التنفيذ البرمجي أصلاً، لأن الراية لم تكن موجودة لمسحها.

رسم بيانيAES-128-GCM throughput, one core, 8192-byte blocks (representative published figures)
البيانات وراء هذا الرسم البياني
[
  {
    "label": "AES-NI and PCLMULQDQ",
    "mb_per_sec": "4,850",
    "cycles_per_byte": 0.7
  },
  {
    "label": "Software fallback",
    "mb_per_sec": 310,
    "cycles_per_byte": 11.0
  }
]

هذه أرقام منشورة تمثيلية لنواة x86 حديثة بتردد يقارب 3.4 GHz، وليست قياساً مأخوذاً من خادم محدد. اقرأها بوصفها نمطاً عاماً. يعمل مسار العتاد بنحو 0.7 دورة لكل بايت، بينما يعمل المسار البرمجي الاحتياطي بنحو 11.0، أي ما يعادل نحو 4,850 MB/s مقابل 310 MB/s على نواة واحدة. يعطيك الأمران أعلاه الرقم الوحيد الذي يصف خادمك. وينطبق المبدأ نفسه على بقية الجهاز، لذلك اربط هذا بـطريقة قابلة للتكرار لقياس أداء VPS قبل استخلاص استنتاجات عن الخطة.

إعادة تفعيل البتات باستخدام OPENSSL_ia32cap

هذا هو الجزء الذي يفاجئ كثيراً من الأشخاص. تعليمات AES-NI غير مميّزة، ولا يعترضها برنامج مراقبة الأجهزة الافتراضية. الاعتراض يطال CPUID فقط. لذلك يمكن للمضيف أن يخبر ضيفك بأن AES-NI غير موجود، بينما تواصل AESENC التنفيذ محلياً بالسرعة الكاملة. يتجاوز البرنامج المسار السريع لأنه استعلم عن CPUID وتلقى إجابة غير صحيحة. أما التعليمة نفسها فلم تتوقف عن العمل.

يتيح لك OpenSSL الإجابة نيابةً عن وحدة المعالجة المركزية. تؤدي قيمة سداسية عشرية عادية في OPENSSL_ia32cap إلى استبدال متجه القدرات، لا إلى حجبه.

OPENSSL_ia32cap="0x0200020207000000" openssl speed -evp aes-128-gcm

إذا كان هذا التنفيذ أسرع بعدة مرات من التنفيذ العادي، فهذا يعني أن العتاد يحتوي على AES-NI وأن المضيف يخفيه. هذا تشخيص أولاً. وبالنسبة إلى OpenSSL، فهو يُعد أيضاً إصلاحاً.

كيفية إنشاء هذه القيمة السداسية عشرية

يعبّئ المتجه المنطقي الأول قيمة EDX من CPUID leaf 1 في أقل 32 بت، وقيمة ECX من leaf 1 في أعلى 32 بت. في النصف الأدنى، البت 24 هو FXSR، والبت 25 هو SSE، والبت 26 هو SSE2، ما يعطي 0x07000000. وفي النصف الأعلى، البت 33 هو PCLMULQDQ، والبت 41 هو SSSE3، والبت 57 هو AES-NI، ما يعطي 0x02000202. وبجمعهما تصبح القيمة 0x0200020207000000. أُدرج SSSE3 لأن GHASH القائم على PCLMULQDQ في OpenSSL يستخدم pshufb لتبديل البايتات، ولأن نموذج وحدة معالجة مركزية عاماً للضيف يخفي SSSE3 إلى جانب AES-NI.

ينطبق تحذيران، ويمكنك التسبب بهما عمداً.

يؤدي ضبط المتجه الأول فقط إلى ترك المتجهات اللاحقة بقيمة صفر، ما يعطّل مساري AVX2 وAVX-512. هذا مقصود هنا. لا تحاول فرض تفعيل بتات AVX على ضيف محجوب، لأن سجلات AVX تحتاج إلى أن يفعّل نظام التشغيل الحالة الموسّعة في XCR0، وقد رفضت النواة ذلك استناداً إلى CPUID المحجوب نفسه. عندها ترفع تعليمة بترميز VEX خطأ تعليمة غير معرّفة، وتنتهي العملية.

يؤدي فرض تفعيل AES-NI على نواة تفتقر إليه فعلياً إلى إنهاء العملية فوراً:

Illegal instruction (core dumped)

هذا يعني أن AESENC رفع خطأ تعليمة غير معرّفة، لأن تلك النواة لا تحتوي على هذه التعليمة لتنفيذها. ويمكن لبعض البرامج الثابتة للخوادم أيضاً تعطيل AES-NI على مستوى العتاد حتى إعادة التشغيل التالية، وتكون الأعراض متطابقة. في كلتا الحالتين، الحل هو استخدام مضيف مختلف، وليس متغير بيئة مختلفاً.

للحفاظ على هذا التجاوز لخدمة تعمل فترة طويلة، استخدم drop-in في systemd.

sudo systemctl edit nginx
[Service]
Environment="OPENSSL_ia32cap=0x0200020207000000"
sudo systemctl daemon-reload
sudo systemctl restart nginx
sudo systemctl show nginx -p Environment

يجب أن يعرض الأمر الأخير المتغير مرة أخرى. افهم ما الذي تلتزم به: إذا نُقل ذلك الخادم يوماً إلى مضيف تفتقر وحدة المعالجة المركزية فيه فعلياً إلى AES-NI، فسيتوقف nginx بسبب تعليمة غير قانونية عند أول اتصال TLS. أضف ذلك إلى runbook، أو اترك التجاوز خارج بيئة الإنتاج تماماً، واستخدمه فقط لإثبات المشكلة عند فتح تذكرة.

ما الذي لا يُصلحه override

يصل OPENSSL_ia32cap إلى OpenSSL ولا يصل إلى أي شيء آخر. يُجري كل برنامج آخر اكتشاف الميزات الخاص به، ولا يقرأ هذا المتغير مطلقاً.

النواة هي الحالة المهمة. يستخدم dm-crypt وLUKS واجهة تشفير النواة، وترفض الوحدة aesni_intel التحميل عندما تكون بتّات ميزات المعالج مفقودة:

modprobe: ERROR: could not insert 'aesni_intel': No such device

لا يوجد متغير في مساحة المستخدم لهذا الغرض. تقرأ النواة CPUID مرة واحدة عند الإقلاع، ويظل هذا القرار سارياً حتى تعيد التشغيل على مضيف مختلف. لذلك يظل المجلد المشفّر يستخدم الشيفرة البرمجية، مهما كان OpenSSL يفعل. قِس ما تحصل عليه فعلياً:

sudo cryptsetup benchmark -c aes-xts -s 256

يعطي صف aes-xts 256b نتائج بآلاف MiB/s مع AES العتادي، وبضع مئات فقط من MiB/s من دونه. كما يتعذر التأثير في بيئات اللغة التي تجري اكتشافها الخاص، ومنها Go وJava. يفحص crypto/aes في Go تعليمات CPUID مباشرة، وينتقل بصمت إلى تطبيقه البرمجي العام عندما يكون البت غير مفعّل. وتذكر وثائق الحزمة أن هذا التطبيق ليس ثابت الزمن. إذا كانت الخدمة التي تنهي TLS ملفاً تنفيذياً مكتوباً بلغة Go، فلن يغير متغير OpenSSL أي شيء فيها.

إذا تعذر عليك الحصول على AES-NI، فاستخدم ChaCha20

صُممت ChaCha20-Poly1305 لتكون سريعة عند تنفيذها بالبرمجيات العادية. على نواة لا يتوفر فيها AES-NI قابل للاستخدام، تتفوق عادةً على AES-GCM بفارق كبير. لذلك فإن الإجراء المنطقي على هذا المضيف هو التوقف عن تفضيل AES.

بالنسبة إلى nginx 1.19.4 والإصدارات الأحدث، عند بنائه باستخدام OpenSSL 1.1.1 أو إصدار أحدث:

ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384;

يغطي ssl_ciphers بروتوكول TLS 1.2. ويغطي ssl_conf_command Ciphersuites بروتوكول TLS 1.3، حيث لا يملك nginx توجيهاً مخصصاً ويمرر السلسلة إلى OpenSSL. يتحقق nginx من استجابة OpenSSL: يؤدي اسم توجيه مكتوب بشكل خاطئ، أو قائمة لا يتعرف OpenSSL فيها على أي حزمة، إلى إيقاف تحميل الإعداد مع خطأ SSL_CONF_cmd(...) failed بمستوى emerg. يتجاوز OpenSSL 3 بصمت اسم حزمة غير معروف واحداً داخل قائمة صالحة، لذلك قد يختفي الخطأ الإملائي في اسم واحد دون تحذير. أعد التحميل وتحقق مما يُعرض على العميل:

sudo nginx -t && sudo systemctl reload nginx
openssl s_client -connect example.com:443 -tls1_3 </dev/null 2>/dev/null | grep -i cipher

تذكر النتيجة السليمة TLS_CHACHA20_POLY1305_SHA256. قبل اعتماد التغيير، شغّل openssl speed -evp chacha20-poly1305 بجانب اختبار AES على المضيف نفسه، ودع الرقمين يحسمان القرار.

تستخدم مضيفات ARM امتدادات مختلفة

تدعم AES-NI معمارية x86 فقط. ويستخدم VPS يعمل على ARM امتدادات ARMv8 التشفيرية، وهي مجموعة تعليمات منفصلة تؤدي المهمة نفسها. في aarch64، توجد الرايات ضمن Features بدلاً من flags:

grep -m1 Features /proc/cpuinfo

ابحث عن aes وpmull. يمثّل pmull النظير الخاص بـARM من PCLMULQDQ، ويحتاج GCM إليه للسبب نفسه. ومتغير التجاوز في OpenSSL على ARM هو OPENSSL_armcap، مع تخطيط بتات خاص به معرّف في crypto/arm_arch.h ضمن مصدر OpenSSL، لذلك لا تعني قيمة hexadecimal الخاصة بـx86 الواردة في هذا الدليل شيئاً على ARM. عملياً، تعرض نوى خوادم ARM المباعة كمضيفات VPS هذه الامتدادات، ولذلك ترتبط مشكلة الميزات المحجوبة غالباً بمعمارية x86.

أنماط الفشل، مع النصوص التي ستظهر لك

لا يظهر aes في /proc/cpuinfo، ويكون التشغيل القسري أسرع بكثير. يخفي المضيف معلومات CPUID. تأكد من أن اسم الطراز عاماً، ثم اسأل مزود الخدمة عن طراز CPU الضيف الذي يقدمه برنامج hypervisor لديه.

لا يظهر aes في /proc/cpuinfo، ويعرض التشغيل القسري Illegal instruction. التعليمات غير متاحة فعلياً، أو عطّلها البرنامج الثابت. انقل عبء العمل إلى مضيف آخر.

يوجد aes، لكن معدل النقل لا يزال منخفضاً. تحقق من أنك تقرأ عمود 8192 بايت، ومن عدم استخدام أي شيء آخر للنواة. في الخطط المشتركة، يبدو الجار المزعج تماماً مثل ميزة CPU مفقودة إلى أن تشغّل الاختبار مرتين في وقتين مختلفين من اليوم.

يعطي التشغيل المقنّع والتشغيل العادي الرقم نفسه. كان OpenSSL يستخدم مسار البرامج بالفعل. هذه النتيجة هي ما يجب اكتشافه، وليست خطأً في الاختبار.

تغيّر المحاكاة الافتراضية المتداخلة الإجابة في المستوى الأدنى. يحصل الضيف داخل ضيف على معلومات CPUID التي اختارت الطبقة الوسطى تمريرها، ومن السهل فقدان AES-NI هناك دون ملاحظة ذلك. إذا كنت تشغّل آلات افتراضية متداخلة على VPS، فتحقق من العلم داخل الضيف الداخلي وكذلك على الجهاز الذي استأجرته.

FAQ

لماذا لا يحتوي VPS لدي على علامة aes في /proc/cpuinfo؟

لأن hypervisor يعرض نموذجاً عاماً لوحدة المعالجة المركزية للضيف. لا يتضمن qemu64 وkvm64 AES-NI ضمن مجموعات ميزاتهما، لذلك يبلغ CPUID عن غيابها مهما كان المعالج الفعلي. تفعل المضيفات ذلك حتى يمكن ترحيل الضيف قيد التشغيل بين أجهزة ذات معالجات مختلفة. شغّل grep -m1 'model name' /proc/cpuinfo: فالسلسلة مثل QEMU Virtual CPU version 2.5+ أو Common KVM processor هي المؤشر. تعني سلسلة نموذج Xeon أو EPYC حقيقية أن نموذج المعالج مُمرَّر كما هو، لكن هذه المعالجات تتضمن AES-NI عتادياً؛ إذ تسرد مواصفات Intel لمعالج Xeon Gold 6338 هذه الميزة. لذلك يعني غياب العلامة هناك أن hypervisor حجب بت الميزة هذا تحديداً. يوضح تشغيل OPENSSL_ia32cap القسري أعلاه ما إذا كانت التعليمات لا تزال تُنفَّذ.

هل يفعّل OPENSSL_ia32cap فعلاً AES-NI، أم أنه يتظاهر بذلك فقط؟

إنه يفعّل التعليمات الفعلية. تعليمات AES-NI غير مميّزة، ولا يعترض hypervisor تنفيذها. لذلك ينفّذ AESENC التعليمات محلياً مهما كانت نتيجة CPUID. لا يُعترض سوى تعليمة CPUID. يؤدي ضبط OPENSSL_ia32cap على قيمة سداسية عشرية عادية إلى استبدال النتيجة التي حصل عليها OpenSSL من CPUID. عندها يختار OpenSSL مسار الشيفرة العتادية، وينفذه العتاد بالسرعة الكاملة. إذا كان السيليكون يفتقر فعلاً إلى هذه التعليمات، تنتهي العملية بالخطأ Illegal instruction (core dumped) عند أول عملية AES.

هل يؤدي هذا التجاوز إلى تسريع مجلد LUKS المشفّر؟

لا. يقرأ OpenSSL OPENSSL_ia32cap ولا يقرأه أي مكوّن آخر. يستخدم LUKS وdm-crypt واجهة تشفير النواة، حيث تفشل الوحدة aesni_intel في التحميل مع modprobe: ERROR: could not insert 'aesni_intel': No such device عندما يكون بت الميزة غير مفعّل. تقرأ النواة CPUID عند الإقلاع، ولا يغير أي متغير في مساحة المستخدم ذلك. قِس القيمة الفعلية باستخدام sudo cryptsetup benchmark -c aes-xts -s 256، وقارن صف aes-xts 256b بمضيف يبلّغ عن وجود العلامة.

هل يؤدي غياب علامة AES-NI إلى إبطاء WireGuard؟

لا. يستخدم WireGuard ChaCha20-Poly1305 لجميع البيانات، ولا يستخدم تعليمات AES مطلقاً. لذلك تكون سرعة النقل متساوية على المضيف الذي حُجبت فيه الميزة وعلى المضيف الذي لم تُحجب فيه. أما OpenVPN وIPsec، عند إعدادهما باستخدام AES-GCM، فيفقدان جزءاً من سرعة النقل على مضيف يفتقر إلى AES-NI. لذلك قد يتصرف نفقان على VPS نفسه بشكل مختلف جداً، ومن المفيد معرفة ذلك قبل إلقاء اللوم على الشبكة.

كيف أتحقق من وجود AES-NI على VPS يعمل بمعمارية ARM؟

لا تحتوي أنوية ARM على AES-NI. بل تحتوي على امتدادات التشفير ARMv8، التي تؤدي الوظيفة نفسها باستخدام تعليمات مختلفة. شغّل grep -m1 Features /proc/cpuinfo وابحث عن aes وpmull، لأن aarch64 يسردهما ضمن Features بدلاً من flags. لا تحمل قيمة OPENSSL_ia32cap الخاصة بـ x86 أي معنى على ARM. والمتغير المكافئ في OpenSSL هناك هو OPENSSL_armcap، ويُحدَّد تخطيط بتاته في crypto/arm_arch.h ضمن مصدر OpenSSL.

هل كان هذا المقال مفيدًا؟