eBPF: كيف أصبح Linux نواةً آمنةً وسريعةً وقابلةً للبرمجة

المشكلة مع الطريقة القديمة
لعقود طويلة، إن أردت تغيير طريقة تعامل نواة Linux مع الحزم، أو تصفية استدعاءات النظام، أو تتبع اختناقات الأداء، كان أمامك خياران لا ثالث لهما: إما تقديم تعديل على النواة والانتظار سنوات حتى يُدرَج في التوزيعات، أو كتابة وحدة نواة (kernel module). وحدات النواة قوية لكنها خطرة؛ فأي خطأ فيها يُوقف الخادم بالكامل. وهي مرتبطة بإصدار النواة تحديداً، فالوحدة المبنية للإصدار 5.15 تتعطل على الإصدار 6.1. ونشرها عبر أسطول غير متجانس يعني صيانة عشرات البنيات المختلفة. بالنسبة لشركة تُشغِّل مئات الآلاف من الخوادم، لا يُعدُّ هذا مشكلة هندسية فحسب — بل هو التزام ومسؤولية قانونية.
يحلّ eBPF هذه المعضلة. إذ يتيح لك حقن منطق مخصص في النواة الجارية — سواء للشبكات أو الأمان أو الرصد — بشكل آمن وقابل للنقل، دون الحاجة إلى إعادة تشغيل أي شيء.
ما الذي يكونه eBPF فعلاً
أُنشئ BPF (Berkeley Packet Filter) عام 1992 لتسريع tcpdump. بدلاً من نسخ كل حزمة إلى فضاء المستخدم (userspace) لتصفيتها، كان BPF يُشغِّل آلة افتراضية صغيرة داخل النواة لتصفية الحزم في مكانها. كان محدود النطاق بتصميم متعمَّد.
في عام 2014، أدخل Alexei Starovoitov وDaniel Borkmann extended BPF في Linux 3.18. أُعيد تصميم مجموعة التعليمات لتناسب البنيات 64 بت، وتوسَّع عدد السجلات، و— الأهم — تضاعفت نقاط التعلق (hook points) بشكل كبير متجاوزةً تصفية الحزم. اليوم يمكنك ربط برامج eBPF بمسارات الشبكة الواردة والصادرة، ونقاط التتبع (tracepoints)، ومجسّات kprobes (مجسّات دوال النواة الديناميكية)، وuprobes (مجسّات دوال فضاء المستخدم)، ونقاط دخول وخروج استدعاءات النظام. أصبحت النواة قابلة للبرمجة.
نموذج الأمان هو ما يجعل هذا قابلاً للاستخدام في بيئة الإنتاج. تكتب برنامج eBPF بلغة C مقيَّدة، أو باستخدام مكتبات Go أو Rust تُصدر bytecode الخاص بـ eBPF. قبل تشغيل البرنامج، يُحلِّل المُحقِّق (verifier) في النواة كل مسار تنفيذ محتمل بشكل ثابت: لا حلقات غير محدودة، ولا وصول للذاكرة خارج النطاق، ولا عمليات حسابية غير آمنة على المؤشرات. تُرفَض البرامج التي تفشل في التحقق كلياً. أما البرامج التي تجتازه فتُجمَّع بتقنية JIT إلى شيفرة آلة أصيلة — مما يعني غياب أي عبء للمُفسِّر (interpreter) أثناء التشغيل. والنتيجة هي شيفرة تعمل داخل النواة بسرعة شبه أصيلة، مع ضمانات أمان تُطبِّقها النواة تلقائياً.
XDP وثورة الشبكات
أكثر قدرات eBPF إثارةً لفرق البنية التحتية هي XDP — eXpress Data Path. تعمل خطافات XDP قبل أن تُعالج حزمة الشبكات في النواة. قبل تخصيص sk_buff. قبل البحث في جدول التوجيه. قبل أي شيء. يستطيع برنامج XDP إسقاط أي حزمة أو إعادة توجيهها أو تعديلها في طبقة مشغِّل واجهة الشبكة (NIC driver) بمعدل يتجاوز 100 مليون حزمة في الثانية على أجهزة رخيصة التكلفة.
في مجال الدفاع ضد هجمات DDoS، يُغيِّر هذا كل شيء. الهجوم الحجمي الذي كان سيُشبع مسار الشبكة الطبيعي للنواة — مملئاً طوابير المقابس، ومُستنزِفاً المعالج في معالجة المقاطعات — يُسقَط الآن على مستوى المشغِّل قبل أن يحدث أي من ذلك العبء. تستخدم Cloudflare برامج eBPF المبنية على XDP لاستيعاب هجمات DDoS على نطاق التيرابت. لا تصل الحزمة إلى الحزمة إلى المكدس أبداً. يظل الخادم يعمل.
ذهبت Meta أبعد من ذلك. فقد استبدلت بنيتها التحتية بالكامل لموازنة الحِمل — المبنية سابقاً على IPVS — بـ Katran، موازن حِمل مفتوح المصدر يعتمد على eBPF/XDP. يعمل Katran على كل خادم في مراكز بيانات Meta، مُعالِجاً حركة مرور بحجم Facebook دون الحاجة إلى أجهزة موازنة حِمل مخصصة. تعني مرونة eBPF أنهم يستطيعون تحديث منطق موازنة الحِمل عبر تحميل برنامج جديد، لا عبر إعادة التشغيل أو إعادة نشر الأجهزة.
شبكات Kubernetes عبر Cilium
مشكلة شبكات Kubernetes معقدة. كل pod يحتاج عنوان IP. تحتاج الـ pods إلى التواصل عبر العقد (nodes). تحتاج سياسات الشبكة إلى التطبيق. يجب أن تحدث موازنة حِمل الخدمات. كانت الإجابة التقليدية هي iptables — محرك قواعد لا يتوسع جيداً. عند بضعة آلاف من القواعد، يصبح البحث في iptables من الترتيب O(n) وترتفع استهلاك المعالج بشكل واضح. عند عشرات الآلاف من الـ pods، ينهار الأمر.
يستبدل Cilium iptables كلياً بـ eBPF. يحدث توجيه pod إلى pod، وموازنة حِمل الخدمات، وتطبيق سياسة الشبكة كلها في برامج eBPF مربوطة بواجهات الشبكة. عمليات البحث من الترتيب O(1) عبر خرائط هاش eBPF. يحدث تطبيق السياسة في المسار السريع للنواة. يفهم Cilium أيضاً HTTP وgRPC وKafka على الطبقة السابعة (Layer 7) — لأن برامج eBPF تستطيع فحص حمولات الحزم، لا مجرد رؤوسها.
التبني يقول الكثير. AWS EKS وGoogle GKE وAzure AKS جميعها تقدم Cilium كـ CNI افتراضي أو موصى به. عناقيد Kubernetes التي تُشغِّل مئات العقد مع آلاف الـ pods تستخدم eBPF لكل قرار يتعلق بالحزم، وقد اختفى اختناق iptables.
الرصد دون الحاجة إلى إضافة أدوات قياس
تتطلب أدوات APM التقليدية تغييرات في الشيفرة: إضافة مكتبة، وتغليف الدوال، وإعادة النشر. لا يتطلب رصد eBPF شيئاً من ذلك. تربط kprobe أو uprobe بأي دالة في النواة أو فضاء المستخدم وتجمع البيانات — زمن الاستجابة، والمعطيات، وقيم الإرجاع، ومسارات المكدس — دون تعديل التطبيق.
تستخدم Netflix أداة bpftrace في الإنتاج لهذا الغرض تحديداً. bpftrace هي لغة برمجة نصية عالية المستوى لـ eBPF، تشبه ما كانت عليه DTrace على Solaris. يمكن لسطر واحد تتبع كل عملية I/O على القرص تتجاوز 1ms على خادم إنتاجي، أو رسم رسوم بيانية لزمن استجابة اتصالات TCP، أو معرفة العمليات التي تُسبِّب أكثر تبديلات السياق — كل ذلك بعبء يُقاس بنسب مئوية أحادية الرقم، لا بتكلفة 10-30% للتنميط التقليدي.
تأخذ Pixie هذا أبعد في سياق Kubernetes، إذ تُجهِّز كل خدمة في العنقود تلقائياً باستخدام eBPF لالتقاط بيانات الطلب والاستجابة، وتوزيعات زمن الاستجابة، ومعدلات الأخطاء دون أي تهيئة لكل خدمة على حدة. لا sidecars. لا تكامل SDK. الرصد مُدمَج في طبقة النواة.
تطبيق الأمان على مستوى النواة
يُصفِّي seccomp-BPF استدعاءات النظام في حاويات Linux منذ سنوات — فهو ما تستخدمه Docker وChrome وFirefox لتقييد استدعاءات النظام التي يمكن لعملية معزولة إجراؤها. هذا هو الطرف الضيق من أمان eBPF.
الطرف الأوسع هو تطبيق الأمان في وقت التشغيل. تستخدم Falco eBPF لمراقبة كل استدعاء نظام في عنقود Kubernetes والتنبيه على السلوك المشبوه — حاوية تُولِّد shell، أو عملية تكتب في /etc، أو اتصال شبكي بعنوان IP غير متوقع. تذهب Tetragon، من مشروع Cilium، أبعد من ذلك: لا تكتفي بالكشف عن انتهاكات السياسة في الوقت الفعلي بل تُطبِّقها بإنهاء العملية المخالفة قبل اكتمال استدعاء النظام. يعمل منطق السياسة في النواة عبر eBPF. لا توجد نافذة سباق (race window) بين الكشف والاستجابة.
قابلية النقل: CO-RE وBTF
كانت الشكوى المتبقية حول eBPF هي الارتباط بإصدار معين من النواة. فبرنامج eBPF مُجمَّع بحسب رؤوس النواة 5.15 قد لا يعمل على 6.1 إن تغيَّرت تخطيطات البنى (struct layouts). يحلّ CO-RE — Compile Once, Run Everywhere هذه المشكلة. مع BTF (BPF Type Format)، تُعرِّض النواة معلومات نوعها الداخلية في وقت التشغيل. يستخدم مُحمِّل eBPF البيانات من BTF لإعادة توطين الوصول إلى الحقول عند التحميل، مُكيِّفاً البرنامج المُجمَّع مع أي نواة تعمل فعلياً. يستطيع ملف eBPF الثنائي الواحد الآن العمل عبر أسطول كامل متعدد الأنوية دون إعادة تجميع.
ما الذي يأتي بعد ذلك
تعمل Microsoft بنشاط على نقل eBPF إلى Windows عبر مشروع ebpf-for-windows. يُضيف مصنِّعو SmartNIC إمكانية التفريغ على العتاد لبرامج eBPF، بحيث يمكن تصفية XDP على الـ NIC نفسه، مُحرِّراً معالجات الخادم المضيف كلياً. تنضج بيئات تشغيل eBPF في فضاء المستخدم، مما يُتيح قابلية التوسع المعزولة بأسلوب eBPF خارج النواة.
النمط الأساسي ثابت: آلية توسع قابلة للبرمجة مع ضمانات أمان قوية تتفوق على شيفرة النواة الثابتة في كل ما يحتاج إلى التطور بسرعة الإنتاج. لم يُحسِّن eBPF شبكات Linux ورصدها فحسب — بل غيَّر النموذج المتبع لتوسيع سلوك النواة. فرق البنية التحتية التي فهمت ذلك مبكراً تعمل بسرعة أكبر وأمان أعلى وعلى نطاق أوسع من تلك التي ما زالت تكتب قواعد iptables ووحدات النواة.