أداة 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 هو اسم
حدث التتبُّع. اطّلِع على مستندات ملف kernel
لأحداث التتبّع للحصول على مزيد من المعلومات عن نقاط التتبّع.
|
فلتر 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 برنامج .c
باستخدام eBPF، عليك
إنشاء إدخال في ملف 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 المنخفضة المستوى المطلوبة.
لإنشاء الخرائط وقراءتها، وإنشاء المسابر ونقاط التتبع، والموارد الاحتياطية للأداء.
إرفاق البرامج بنقاط التتبع
يتم تحميل برامج نقاط التتبُّع تلقائيًا عند بدء التشغيل. بعد التحميل، يجب تفعيل برنامج tracepoint باتّباع الخطوات التالية:
- يُرجى الاتصال برقم
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 في ترددات وحدة المعالجة المركزية (CPU)، والتي تُستخدم لحساب الطاقة.في Android 12، تم ضبط
gpu_mem
eBPF C البرنامج يتتبع إجمالي استخدام ذاكرة وحدة معالجة الرسومات لكل عملية ولكل النظام. هذا النمط في تحليل الذاكرة عبر وحدة معالجة الرسومات.