เครื่องมือการรับส่งข้อมูลเครือข่าย 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
โครงสร้างพื้นฐานใหม่นี้มีความยืดหยุ่นและสามารถบำรุงรักษาได้มากกว่า และไม่ต้องใช้โค้ดเคอร์เนลที่ไม่อยู่ในโครงสร้าง
ความแตกต่างด้านการออกแบบที่สำคัญระหว่างการตรวจสอบการรับส่งข้อมูลแบบเดิมและ eBPF แสดงไว้ในรูปที่ 1
รูปที่ 1. ความแตกต่างของการออกแบบการตรวจสอบการรับส่งข้อมูลแบบ Legacy (ซ้าย) และ eBPF (ขวา)
การออกแบบ trafficController
ใหม่นั้นใช้ตัวกรอง cgroup
สำหรับแต่ละกลุ่ม เช่นเดียวกับโมดูล xt_bpf
netfilter ภายในเคอร์เนล ตัวกรอง eBPF เหล่านี้ใช้กับแพ็กเก็ต tx/rx เมื่อผ่านตัวกรอง ตัวกรอง cgroup
eBPF ตั้งอยู่ที่ชั้นการขนส่งและรับผิดชอบในการนับการรับส่งข้อมูลกับ UID ที่ถูกต้องโดยขึ้นอยู่กับ UID ของซ็อกเก็ตรวมถึงการตั้งค่าพื้นที่ผู้ใช้ xt_bpf
netfilter ถูกต่อเข้ากับ bw_raw_PREROUTING
และ bw_mangle_POSTROUTING
และรับผิดชอบในการนับทราฟฟิกกับอินเทอร์เฟซที่ถูกต้อง
ในเวลาบูต TrafficController ของกระบวนการ userspace จะสร้างแผนที่ trafficController
ที่ใช้สำหรับการรวบรวมข้อมูลและปักหมุดแผนที่ทั้งหมดเป็นไฟล์เสมือนที่ sys/fs/bpf
จากนั้นกระบวนการที่มีสิทธิพิเศษ bpfloader
โหลดโปรแกรม eBPF ที่คอมไพล์ล่วงหน้าลงในเคอร์เนลและแนบเข้ากับ cgroup
ที่ถูกต้อง มี cgroup
รูทเดียวสำหรับการรับส่งข้อมูลทั้งหมด ดังนั้นกระบวนการทั้งหมดควรรวมอยู่ใน cgroup
นั้นโดยค่าเริ่มต้น
ในขณะใช้งาน trafficController
สามารถแท็ก/เลิกแท็กซ็อกเก็ตโดยเขียนไปที่ traffic_cookie_tag_map
และ traffic_uid_counterSet_map
NetworkStatsService
สามารถอ่านข้อมูลสถิติการรับส่งข้อมูลจาก traffic_tag_stats_map
, traffic_uid_stats_map
และ traffic_iface_stats_map
นอกจากฟังก์ชันการรวบรวมสถิติการรับส่งข้อมูลแล้ว trafficController
และตัวกรอง cgroup
eBPF ยังรับผิดชอบในการบล็อกการรับส่งข้อมูลจาก 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 ใหม่
ความต้องการ
การกำหนดค่าเคอร์เนลต้องเปิดการกำหนดค่าต่อไปนี้:
-
CONFIG_CGROUP_BPF=y
-
CONFIG_BPF=y
-
CONFIG_BPF_SYSCALL=y
-
CONFIG_NETFILTER_XT_MATCH_BPF=y
-
CONFIG_INET_UDP_DIAG=y
การ ทดสอบการกำหนดค่าเคอร์เนล VTS มีประโยชน์เมื่อตรวจสอบว่าการกำหนดค่าที่ถูกต้องเปิดอยู่
-
อุปกรณ์
MEM_LOCK
rlimit ต้องตั้งค่าเป็น 8 MB ขึ้นไป
กระบวนการเลิกใช้ xt_qtaguid แบบเดิม
เครื่องมือ eBPF ใหม่กำลังแทนที่โมดูล xt_qtaguid
และโมดูล xt_owner
ที่อิงตาม เราจะเริ่มลบโมดูล xt_qtaguid
ออกจากเคอร์เนล Android และปิดใช้งานการกำหนดค่าที่ไม่จำเป็น
ในรุ่น Android 9 โมดูล xt_qtaguid
จะเปิดอยู่ในอุปกรณ์ทั้งหมด แต่ API สาธารณะทั้งหมดที่อ่านไฟล์ proc ของโมดูล xt_qtaguid
โดยตรงจะถูกย้ายไปยัง NetworkManagement
Service บริการ NetworkManagement
Service ทราบว่าเครื่องมือ eBPF เปิดอยู่หรือไม่ โดยขึ้นอยู่กับเวอร์ชันเคอร์เนลของอุปกรณ์และระดับ API แรก และเลือกโมดูลที่เหมาะสมเพื่อรับสถิติการใช้งานเครือข่ายแอปแต่ละรายการ แอปที่มี SDK ระดับ 28 ขึ้นไปจะถูกบล็อกไม่ให้เข้าถึงไฟล์ xt_qtaguid
proc โดยการแบ่งแยกดินแดน
ใน Android รุ่นถัดไปหลังวันที่ 9 แอปเข้าถึงไฟล์ xt_qtaguid
proc เหล่านั้นโดยสมบูรณ์ เราจะเริ่มลบโมดูล xt_qtaguid
ออกจากเคอร์เนลทั่วไปของ Android ใหม่ หลังจากที่นำออกแล้ว เราจะอัปเดตการกำหนดค่าพื้นฐานของ Android สำหรับเวอร์ชันเคอร์เนลนั้นเพื่อปิดโมดูล xt_qtaguid
อย่างชัดเจน โมดูล xt_qtaguid
จะถูกเลิกใช้โดยสมบูรณ์เมื่อข้อกำหนดเวอร์ชันเคอร์เนลขั้นต่ำสำหรับรุ่น Android คือ 4.9 หรือสูงกว่า
ในรุ่น Android 9 เฉพาะอุปกรณ์ที่เปิดตัวพร้อมกับ Android 9 เท่านั้นที่จะต้องมีฟีเจอร์ eBPF ใหม่ สำหรับอุปกรณ์ที่มาพร้อมกับเคอร์เนลที่สามารถรองรับเครื่องมือ eBPF ได้ เราแนะนำให้อัปเดตเป็นฟีเจอร์ eBPF ใหม่เมื่ออัปเกรดเป็น Android 9 ไม่มีการทดสอบ CTS เพื่อบังคับใช้การอัปเดตนั้น
การตรวจสอบความถูกต้อง
คุณควรใช้แพตช์จากเคอร์เนลทั่วไปของ Android และ Android AOSP master เป็นประจำ ตรวจสอบให้แน่ใจว่าการใช้งานของคุณผ่านการทดสอบ VTS และ CTS ที่เกี่ยวข้อง, netd_unit_test
และ libbpf_test
การทดสอบ
มี เคอร์เนล net_tests เพื่อให้แน่ใจว่าคุณได้เปิดคุณสมบัติที่จำเป็นและแพตช์เคอร์เนลที่จำเป็น backported การทดสอบถูกรวมเป็นส่วนหนึ่งของการทดสอบ VTS รุ่น Android 9 มีการทดสอบหน่วยบางอย่างใน system/netd/
( netd_unit_test
และ libbpf_test
) มีการทดสอบบางอย่างใน netd_integration_test
เพื่อตรวจสอบพฤติกรรมโดยรวมของเครื่องมือใหม่
ตัวตรวจสอบ CTS และ CTS
เนื่องจากทั้งสองโมดูลการตรวจสอบการรับส่งข้อมูลได้รับการสนับสนุนในรุ่น Android 9 จึงไม่มีการทดสอบ 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 ตั้งอยู่ที่:
- https://android.googlesource.com/platform/cts/+/master/tests/tests/net/src/android/net/cts/TrafficStatsTest.java {: .external}
- https://android.googlesource.com/platform/cts/+/master/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java {: .external}
- https://android.googlesource.com/platform/system/netd/+/master/tests/bpf_base_test.cpp {: .external}
การทดสอบ VTS อยู่ที่ https://android.googlesource.com/kernel/tests/+/master/net/test/bpf_test.py
การทดสอบหน่วยตั้งอยู่ที่:
- https://android.googlesource.com/platform/system/netd/+/master/libbpf/BpfNetworkStatsTest.cpp {: .external}
- https://android.googlesource.com/platform/system/netd/+/master/server/TrafficControllerTest.cpp {: .external}