أداة Extended Berkeley Packet Filter (eBPF) هي جهاز افتراضي داخل النواة ينفذ برامج eBPF التي يقدّمها المستخدم لتوسيع وظائف النواة. يمكن ربط هذه البرامج
بعمليات الفحص أو الأحداث في النواة واستخدامها لجمع إحصاءات مفيدة
عن النواة ومراقبتها وتصحيح أخطاءها. يتم تحميل برنامج
في kernel باستخدام طلب نظام التشغيل bpf(2)
، ويقدّمه المستخدم
كمجموعة ثنائية من تعليمات eBPF للآلة. يتيح نظام إنشاء Android compiling compiling C
programs to eBPF باستخدام بنية ملف الإنشاء البسيطة الموضّحة في هذا المستند.
يمكنك الاطّلاع على مزيد من المعلومات حول البنية الداخلية لبروتوكول eBPF وتصميمه على صفحة Brendan Gregg حول eBPF.
يشتمل Android على أداة تحميل eBPF ومكتبة تحمِّل برامج eBPF في وقت التشغيل.
أداة تحميل الملفات BPF في Android
أثناء تشغيل Android، يتم تحميل كل برامج eBPF المتوفّرة في /system/etc/bpf/
. هذه البرامج هي كائنات ثنائية تم إنشاؤها بواسطة نظام إصدار Android من برامج C ومصاحبة بملفات Android.bp
في شجرة مصدر Android. يخزِّن نظام الإنشاء الكائنات التي تم إنشاؤها في /system/etc/bpf
، ويصبح
هذان الكائنان جزءًا من صورة النظام.
تنسيق برنامج eBPF C لنظام التشغيل Android
يجب أن يكون برنامج eBPF C بالتنسيق التالي:
#include <bpf_helpers.h>
/* Define one or more maps in the maps section, for example
* define a map of type array int -> uint32_t, with 10 entries
*/
DEFINE_BPF_MAP(name_of_my_map
, ARRAY, int, uint32_t, 10);
/* this also defines type-safe accessors:
* value * bpf_name_of_my_map_lookup_elem(&key);
* int bpf_name_of_my_map_update_elem(&key, &value, flags);
* int bpf_name_of_my_map_delete_elem(&key);
* as such it is heavily suggested to use lowercase *_map names.
* Also note that due to compiler deficiencies you cannot use a type
* of 'struct foo' but must instead use just 'foo'. As such structs
* must not be defined as 'struct foo {}' and must instead be
* 'typedef struct {} foo'.
*/
DEFINE_BPF_PROG("PROGTYPE/PROGNAME", AID_*, AID_*, PROGFUNC)(..args..) {
<body-of-code
... read or write to MY_MAPNAME
... do other things
>
}
LICENSE("GPL"); // or other license
المكان:
name_of_my_map
هو اسم متغير الخريطة. يُعلم هذا الاسم أداة تحميل BPF بنوع الخريطة المطلوب إنشاؤها وبمَن يلي من المَعلمات. يتوفر تعريف البنية هذا من خلال عنوانbpf_helpers.h
المضمّن.تمثّل السمة
PROGTYPE/PROGNAME
نوع البرنامج واسمه. يمكن أن يكون نوع البرنامج أيًا من الأنواع المدرجة في الجدول التالي. عندما لا يكون نوع البرنامج مُدرَجًا، لا تكون هناك اصطلاحات صارمة لتسميته، بل يجب أن يكون الاسم معروفًا للعملية التي تُرفِق البرنامج.PROGFUNC
هي دالة يتم وضعها في قسم من الملف الناتج عند تجميعها.
kprobe | يتمّ ربط PROGFUNC بتعليمات النواة باستخدام بنية
kprobe. يجب أن يكون PROGNAME هو اسم دالة kernel
التي يتم فحصها. يُرجى الرجوع إلى مستندات kernel kprobe للحصول على مزيد من المعلومات عن
kprobes.
|
---|---|
نقطة التتبّع | ربط PROGFUNC بنقطة تتبُّع يجب أن يكون PROGNAME
بالتنسيق SUBSYSTEM/EVENT . على سبيل المثال، قسم نقطة التتبُّع
لإرفاق الدوالّ بأحداث تبديل سياق المخطِّط سيكون هو
SEC("tracepoint/sched/sched_switch") ، حيث يكون sched هو
اسم النظام الفرعي للتتبُّع، وsched_switch هو اسم
حدث التتبُّع. يمكنك الاطّلاع على وثائق نواة أحداث التتبُّعللحصول على مزيد من المعلومات حول نقاط التتبُّع.
|
skfilter | يعمل البرنامج كفلتر مقبس شبكات. |
جداول زمنية | يعمل البرنامج كمُصنِّف لحركة بيانات الشبكة. |
cgroupskb وcgroupsock | يعمل البرنامج عندما تنشئ العمليات في CGroup مقبسًا AF_INET أو AF_INET6. |
يمكن العثور على أنواع إضافية في Loader الرمز المصدر.
على سبيل المثال، يضيف برنامج myschedtp.c
التالي معلومات عن
رقم تعريف مثيل عملية PID الأخيرة التي تم تشغيلها على وحدة معالجة مركزية معيّنة. يحقّق هذا البرنامج هدفه
من خلال إنشاء خريطة وتحديد دالة tp_sched_switch
يمكن
إرفاقها بحدث التتبّع sched:sched_switch
. لمزيد من المعلومات، اطّلِع على
ربط البرامج بنقاط التتبُّع.
#include <linux/bpf.h> #include <stdbool.h> #include <stdint.h> #include <bpf_helpers.h> DEFINE_BPF_MAP(cpu_pid_map, ARRAY, int, uint32_t, 1024); struct switch_args { unsigned long long ignore; char prev_comm[16]; int prev_pid; int prev_prio; long long prev_state; char next_comm[16]; int next_pid; int next_prio; }; DEFINE_BPF_PROG("tracepoint/sched/sched_switch", AID_ROOT, AID_SYSTEM, tp_sched_switch) (struct switch_args *args) { int key; uint32_t val; key = bpf_get_smp_processor_id(); val = args->next_pid; bpf_cpu_pid_map_update_elem(&key, &val, BPF_ANY); return 1; // return 1 to avoid blocking simpleperf from receiving events } LICENSE("GPL");
تُستخدَم وحدة الماكرو LICENSE للتحقّق مما إذا كان البرنامج متوافقًا مع الترخيص
للنواة عندما يستخدِم البرنامج وظائف المساعدة BPF التي تقدّمها
النواة. حدِّد اسم ترخيص برنامجك في شكل سلسلة، مثل
LICENSE("GPL")
أو LICENSE("Apache 2.0")
.
تنسيق ملف Android.bp
لكي ينشئ نظام إصدار Android برنامج eBPF .c
، عليك
إنشاء إدخال في ملف Android.bp
الخاص بالمشروع. على سبيل المثال، ل
إنشاء برنامج eBPF C باسم bpf_test.c
، أدخِل التالي
في ملف Android.bp
الخاص بمشروعك:
bpf { name: "bpf_test.o", srcs: ["bpf_test.c"], cflags: [ "-Wall", "-Werror", ], }
يُجمِّع هذا الإدخال برنامج C، ما يؤدي إلى إنشاء الكائن
/system/etc/bpf/bpf_test.o
. عند بدء التشغيل، يحمِّل نظام Android تلقائيًا
برنامج bpf_test.o
في النواة.
الملفات المتوفّرة في sysfs
أثناء عملية التشغيل، يحمِّل نظام Android تلقائيًا جميع عناصر eBPF من
/system/etc/bpf/
، وينشئ الخرائط التي يحتاجها البرنامج، ويثبت
البرنامج المحمَّل مع خرائطه في نظام ملفات BPF. ويمكن بعد ذلك استخدام هذه الملفات لمزيد من التفاعل مع برنامج eBPF أو قراءة الخرائط. يصف هذا القسم
الاصطلاحات المستخدَمة لتسمية هذه الملفات ومواقعها في
sysfs.
يتم إنشاء الملفات التالية وتثبيتها:
بالنسبة إلى أي برامج يتم تحميلها، بافتراض أنّ
PROGNAME
هو اسم البرنامج وFILENAME
هو اسم ملف eBPF C، ستنشئ أداة تحميل Android كل برنامج وتثبّته على/sys/fs/bpf/prog_FILENAME_PROGTYPE_PROGNAME
.على سبيل المثال، في المثال السابق عن نقطة تتبُّع
sched_switch
فيmyschedtp.c
، يتم إنشاء ملف برنامج وتثبيته في/sys/fs/bpf/prog_myschedtp_tracepoint_sched_sched_switch
.بالنسبة إلى أيّ خرائط تم إنشاؤها، بافتراض أنّ
MAPNAME
هو اسم الخريطة وFILENAME
هو اسم ملف eBPF C، ينشئ أداة تحميل Android كل خريطة وي يربطها بـ/sys/fs/bpf/map_FILENAME_MAPNAME
.على سبيل المثال، في مثال نقطة التتبّع
sched_switch
السابق فيmyschedtp.c
، يتم إنشاء ملف خريطة وتثبيته في/sys/fs/bpf/map_myschedtp_cpu_pid_map
.يعرض
bpf_obj_get()
في مكتبة BPF على Android واصفًا للملفات من ملف/sys/fs/bpf
المثبَّت. يمكن استخدام واصف الملف هذا لإجراء مزيد من العمليات، مثل قراءة الخرائط أو إرفاق برنامج بنقطة تتبُّع.
مكتبة BPF لنظام التشغيل Android
يُطلق على مكتبة BPF في Android اسم libbpf_android.so
وهي جزء من
صورة النظام. توفّر هذه المكتبة للمستخدم إمكانات eBPF من المستوى الأدنى اللازمة
لإنشاء الخرائط وقراءتها، وإنشاء نقاط الاستكشاف ونقاط التتبّع ووحدات تخزين الأداء.
إرفاق البرامج بنقاط التتبّع
يتم تحميل برامج نقاط التتبُّع تلقائيًا عند بدء التشغيل. بعد التحميل، يجب تفعيل برنامج نقطة التتبّع باتّباع الخطوات التالية:
- يمكنك طلب
bpf_obj_get()
للحصول على البرنامجfd
من موقع الملف المثبَّت. للحصول على مزيد من المعلومات، راجع الملفات المتاحة في sysfs. - استخدِم
bpf_attach_tracepoint()
في مكتبة BPF، مع تمرير البرنامجfd
واسم نقطة التتبُّع.
يوضّح نموذج الرمز البرمجي التالي كيفية إرفاق نقطة تتبُّع sched_switch
المحدّدة في ملف المصدر myschedtp.c
السابق (لا يتم عرض التحقّق من الأخطاء):
char *tp_prog_path = "/sys/fs/bpf/prog_myschedtp_tracepoint_sched_sched_switch"; char *tp_map_path = "/sys/fs/bpf/map_myschedtp_cpu_pid"; // Attach tracepoint and wait for 4 seconds int mProgFd = bpf_obj_get(tp_prog_path); int mMapFd = bpf_obj_get(tp_map_path); int ret = bpf_attach_tracepoint(mProgFd, "sched", "sched_switch"); sleep(4); // Read the map to find the last PID that ran on CPU 0 android::bpf::BpfMap<int, int> myMap(mMapFd); printf("last PID running on CPU %d is %d\n", 0, myMap.readValue(0));
القراءة من الخرائط
تتيح خرائط BPF أنواعًا أو هياكل معقدة عشوائية للمفتاح والقيمة. تتضمّن مكتبة BPF لنظام التشغيل Android فئة android::BpfMap
تستخدِم نماذج C++
لإنشاء مثيل BpfMap
استنادًا إلى نوع المفتاح والقيمة للقائمة المعنيّة. يوضح نموذج الرمز البرمجي السابق استخدام BpfMap
مع مفتاح وقيمة كأعداد صحيحة. يمكن أن تكون الأعداد الصحيحة أيضًا هياكل عشوائية.
وبالتالي، تتيح لك فئة BpfMap
المستندة إلى نموذج تحديد عنصر BpfMap
مخصّص مناسب للخريطة المحدّدة. ويمكن بعد ذلك الوصول إلى الخريطة باستخدام الدوال المُنشأة مخصّصة والتي تكون مدركة للنوع، ما يؤدي إلى إنشاء رمز برمجي أكثر وضوحًا.
لمزيد من المعلومات عن BpfMap
، يُرجى الرجوع إلى
مراجع Android.
تصحيح الأخطاء
أثناء عملية التمهيد، يتم تسجيل عدة رسائل ذات صلة بتحميل BPF. إذا تعذّر اكتمال عملية التحميل لأي سبب، يتم توفير رسالة سجلّ تفصيلية في logcat. يؤدي فلترة سجلّات logcat حسب bpf
إلى طباعة كل الرسائل و
أي أخطاء تفصيلية أثناء وقت التحميل، مثل أخطاء مدقّق eBPF.
أمثلة على تنسيق eBPF في Android
تقدّم البرامج التالية في AOSP أمثلة إضافية لاستخدام eBPF:
يستخدم برنامج
netd
eBPF C الخادم الدائم للشبكة (netd) في Android لأغراض مختلفة، مثل فلترة مآخذ التوصيل وجمع الإحصاءات. للتعرّف على كيفية استخدام هذا البرنامج، راجِع مصادر مراقبة زيارات eBPF.يحسب
time_in_state
برنامج eBPF C المدة التي يقضيها تطبيق Android عند ترددات مختلفة لوحدة المعالجة المركزية، والتي تُستخدَم لحساب الطاقة.في Android 12، يتتبّع
gpu_mem
برنامج eBPF C إجمالي استخدام ذاكرة وحدة معالجة الرسومات في كل عملية وعلى النظام بأكمله. يُستخدَم هذا البرنامج لإنشاء ملف تعريف لذاكرة وحدة معالجة الرسومات.