מעקב אחר תנועת eBPF

כלי התנועה ברשת של eBPF משתמש בשילוב של הטמעה בליבה ובמרחב המשתמש כדי לעקוב אחרי השימוש ברשת במכשיר מאז ההפעלה האחרונה שלו. הוא מספק פונקציונליות נוספת, כמו תיוג שקעים, הפרדת תעבורת נתונים בחזית/ברקע וחומת אש לכל מזהה משתמש (UID) כדי לחסום את הגישה של אפליקציות לרשת בהתאם למצב הטלפון. הנתונים הסטטיסטיים שנאספים מהכלי מאוחסנים במבנה נתונים של הליבה שנקרא eBPF maps, והתוצאה משמשת שירותים כמו NetworkStatsService כדי לספק נתונים סטטיסטיים של תעבורת נתונים מתמשכת מאז האתחול האחרון.

דוגמאות ומקור

השינויים במרחב המשתמש מתבצעים בעיקר בפרויקטים system/netd ו-framework/base. הפיתוח מתבצע ב-AOSP, כך שקוד ה-AOSP תמיד יהיה עדכני. המקור נמצא בעיקר ב-system/netd/server/TrafficController*, ב-system/netd/bpfloader וב-system/netd/libbpf/. חלק מהשינויים הנדרשים במסגרת מופיעים גם ב-framework/base/ וב-system/core.

הטמעה

החל מ-Android 9, במכשירי Android שפועלים עם ליבה מגרסה 4.9 ואילך ושנשלחו במקור עם גרסת P, חובה להשתמש בחישוב מבוסס-eBPF למעקב אחר תעבורת הנתונים ברשת במקום ב-xt_qtaguid. התשתית החדשה גמישה יותר וניתנת לתחזוקה יותר ואין צורך בקוד ליבה (kernel) מחוץ לעץ.

ההבדלים העיקריים בתכנון בין מעקב התנועה הקודם לבין מעקב התנועה באמצעות eBPF מפורטים באיור 1.

הבדלים בתכנון של מעקב אחר תנועה בגרסה הקודמת וב-eBPF

איור 1. ההבדלים בתכנון של מעקב אחר תעבורת נתונים בגרסה הקודמת (שמאל) וב-eBPF (ימין)

העיצוב החדש של trafficController מבוסס על מסנן eBPF לכל cgroup, וגם על מודול netfilter של xt_bpf בתוך הליבה. המסננים האלה של eBPF חלים על ה-tx/rx של החבילות כשהן עוברות דרך המסנן. המסנן cgroup eBPF נמצא בשכבת התעבורה והוא אחראי לספירת התנועה לפי ה-UID הנכון, בהתאם ל-UID של השקע ולהגדרה של מרחב המשתמש. ה-netfilter של xt_bpf מחובר לשרשרת bw_raw_PREROUTING ו-bw_mangle_POSTROUTING, והוא אחראי לספירת התנועה בממשק הנכון.

בזמן האתחול, בתהליך מרחב המשתמשים trafficController נוצר מפות eBPF שמשמשות לאיסוף נתונים, והצמדת כל המפות כקובץ וירטואלי ב-sys/fs/bpf. לאחר מכן, התהליך בעל ההרשאות bpfloader טוען את תוכנית ה-eBPF שעבר הידור מראש לליבה ומצרף אותה ל-cgroup הנכון. יש רק cgroup root אחד לכל התנועה, ולכן כל התהליך צריך להיכלל ב-cgroup הזה כברירת מחדל.

בזמן הריצה, trafficController יכול לתייג או לבטל תיוג של שקע על ידי כתיבה אל traffic_cookie_tag_map ואל traffic_uid_counterSet_map. ה-NetworkStatsService יכול לקרוא את נתוני סטטיסטיקת התנועה מ-traffic_tag_stats_map, מ-traffic_uid_stats_map ומ-traffic_iface_stats_map. מלבד הפונקציה לאיסוף נתונים סטטיסטיים של תנועה, מסנן eBPF trafficController ו-cgroup אחראי גם לחסימת התנועה ממזהי UID מסוימים, בהתאם להגדרות הטלפון. התכונה של חסימה של תעבורת רשתות שמבוססת על UID מחליפה את המודול xt_owner בתוך הליבה, וניתן להגדיר את מצב הפירוט על ידי כתיבת traffic_powersave_uid_map,‏ traffic_standby_uid_map ו-traffic_dozable_uid_map.

ההטמעה החדשה תואמת להטמעה הקודמת של מודול xt_qtaguid, כך ש-TrafficController ו-NetworkStatsService יפעלו עם ההטמעה הקודמת או החדשה. אם האפליקציה משתמשת בממשקי API ציבוריים, לא אמורה להיות לה השפעה אם xt_qtaguid או כלים של eBPF משמשים ברקע.

אם הליבה של המכשיר מבוססת על הליבה המשותפת של Android מגרסה 4.9 (SHA 39c856663dcc81739e52b02b77d6af259eb838f6 ואילך), לא נדרשים שינויים ב-HAL, בקודרים או בקוד הליבה כדי להטמיע את הכלי החדש של eBPF.

הדרישות

  1. בהגדרות הליבה חייבות להיות מופעלות ההגדרות הבאות:

    1. CONFIG_CGROUP_BPF=y
    2. CONFIG_BPF=y
    3. CONFIG_BPF_SYSCALL=y
    4. CONFIG_NETFILTER_XT_MATCH_BPF=y
    5. CONFIG_INET_UDP_DIAG=y

    בדיקת תצורת הליבה של VTS עוזרת לוודא שהתצורה הנכונה מופעלת.

תהליך ההוצאה משימוש של המאפיין xt_qtaguid מדור קודם

הכלי החדש של eBPF מחליף את המודול xt_qtaguid ואת המודול xt_owner שהוא מבוסס עליו. נתחיל להסיר את המודול xt_qtaguid מליבת Android ולהשבית את ההגדרות המיותרות שלו.

במהדורה של Android 9, המודול xt_qtaguid מופעל בכל המכשירים, אבל כל ממשקי ה-API הציבוריים שקוראים ישירות לקובץ ה-proc של המודול xt_qtaguid מועברים לשירות NetworkManagement. בהתאם לגרסה של הליבה של המכשיר ולרמת ה-API הראשונה, השירות NetworkManagement יודע אם הכלים של eBPF מופעלים ובוחר את המודול הנכון לקבלת כל נתון סטטיסטי של שימוש ברשת באפליקציה. אפליקציות עם SDK ברמה 28 ואילך חסרות גישה לקובצי ה-proc של xt_qtaguid על ידי sepolicy.

בגרסה הבאה של Android אחרי 9, הגישה של האפליקציה לקובצי ה-proc האלה של xt_qtaguid תיחסם לחלוטין ונתחיל להסיר את המודול xt_qtaguid מהליבות הנפוצות החדשות של Android. אחרי ההסרה, נעדכן את הגדרת הבסיס של Android לגרסה הזו של הליבה כדי להשבית באופן מפורש את המודול xt_qtaguid. המודול xt_qtaguid יוסר לחלוטין כשדרישת הגרסה המינימלית של הליבה למהדורת Android תהיה 4.9 ואילך.

במהדורת Android 9, רק במכשירים שיושקו עם מהדורת Android 9 תהיה צורך בתכונה החדשה של eBPF. במכשירים שסופקו עם ליבה שיכולה לתמוך בכלים של eBPF, מומלץ לעדכן אותה לתכונה החדשה של eBPF כשמשדרגים לגרסה 9 של Android. אין בדיקת CTS לאכיפת העדכון הזה.

אימות

מומלץ להשתמש באופן קבוע בתיקונים מליבת Android הנפוצה ומ-Android AOSP main. מוודאים שההטמעה עוברת את בדיקות VTS ו-CTS הרלוונטיות, netd_unit_test ו-libbpf_test.

בדיקה

יש net_tests של הליבה כדי לוודא שהתכונות הנדרשות מופעלות ותיקוני הליבה הנדרשים הועברו לגרסאות קודמות. הבדיקות משולבות כחלק מבדיקות VTS של Android 9. יש כמה בדיקות יחידה ב-system/netd/ (netd_unit_test ו-libbpf_test). יש כמה בדיקות ב-netd_integration_test כדי לאמת את ההתנהגות הכוללת של הכלי החדש.

CTS ומאמת CTS

מאחר ששני המודולים למעקב אחר תעבורת הנתונים נתמכים במהדורה 9 של Android, אין בדיקת CTS שמאלצת הטמעה של המודול החדש בכל המכשירים. עם זאת, במכשירים עם גרסת ליבה גבוהה מ-4.9 ששווקו במקור עם גרסת Android 9 (כלומר, רמת ה-API הראשונה שגדולה מ-28), יש בדיקות CTS ב-GSI כדי לאמת שהמודול החדש מוגדר בצורה נכונה. אפשר להשתמש בבדיקות CTS ישנות כמו TrafficStatsTest,‏ NetworkUsageStatsTest ו-CtsNativeNetTestCases כדי לוודא שההתנהגות תואמת למודול ה-UID הישן.

בדיקה ידנית

יש כמה בדיקות יחידה ב-system/netd/ (netd_unit_test,‏ netd_integration_test ו-libbpf_test). יש תמיכה ב-dumpsys לבדיקה ידנית של הסטטוס. הפקודה dumpsys netd מציגה את הסטטוס הבסיסי של המודול trafficController ואת הסטטוס של הפעלת eBPF. אם eBPF מופעל, הפקודה dumpsys netd trafficcontroller מציגה את התוכן המפורט של כל מפת eBPF, כולל מידע על שקע מתויג, נתונים סטטיסטיים לכל תג, UID ו-iface והתאמת UID של הבעלים.

מיקומי בדיקה

בדיקות CTS ממוקמות בכתובת:

בדיקות VTS נמצאות בכתובת https://android.googlesource.com/kernel/tests/+/main/net/test/bpf_test.py.

בדיקות היחידה נמצאות בכתובת: