การตรวจสอบการรับส่งข้อมูล 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 โครงสร้างพื้นฐานใหม่มีความยืดหยุ่นมากขึ้นและบำรุงรักษาได้มากขึ้น และไม่ต้องใช้โค้ดเคอร์เนลที่อยู่นอกแผนผัง

ความแตกต่างในการออกแบบที่สำคัญระหว่างการตรวจสอบการรับส่งข้อมูลแบบเดิมและ eBPF แสดงไว้ในรูปที่ 1

ความแตกต่างในการออกแบบการมอนิเตอร์ทราฟฟิกแบบดั้งเดิมและ eBPF

รูปที่ 1. ความแตกต่างในการออกแบบการมอนิเตอร์ทราฟฟิกแบบดั้งเดิม (ซ้าย) และ eBPF (ขวา)

การออกแบบ trafficController ใหม่นั้นใช้ตัวกรอง eBPF ของกลุ่ม cgroup และโมดูล netfilter xt_bpf ภายในเคอร์เนล ตัวกรอง eBPF เหล่านี้จะใช้กับแพ็กเก็ต tx/rx เมื่อผ่านตัวกรอง ตัวกรอง cgroup eBPF อยู่ที่เลเยอร์การขนส่ง และมีหน้าที่รับผิดชอบในการนับการรับส่งข้อมูลกับ UID ที่ถูกต้อง ขึ้นอยู่กับ UID ของซ็อกเก็ตตลอดจนการตั้งค่าพื้นที่ผู้ใช้ xt_bpf netfilter เชื่อมต่ออยู่ที่เชน bw_raw_PREROUTING และ bw_mangle_POSTROUTING และมีหน้าที่รับผิดชอบในการนับการรับส่งข้อมูลกับอินเทอร์เฟซที่ถูกต้อง

ในเวลาบูต กระบวนการ trafficController ของ userspace จะสร้างแมป eBPF ที่ใช้สำหรับรวบรวมข้อมูลและปักหมุดแมปทั้งหมดเป็นไฟล์เสมือนที่ 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 และตัวกรอง eBPF 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 Service ขึ้นอยู่กับเวอร์ชันเคอร์เนลของอุปกรณ์และระดับ API แรก NetworkManagement Service จะทราบว่าเครื่องมือ eBPF เปิดอยู่หรือไม่ และเลือกโมดูลที่เหมาะสมสำหรับสถิติการใช้งานเครือข่ายแอปแต่ละรายการ แอปที่มี SDK ระดับ 28 ขึ้นไปจะถูกบล็อกไม่ให้เข้าถึงไฟล์ xt_qtaguid proc โดย sepolicy

ใน Android รุ่นถัดไปหลังจากวันที่ 9 การเข้าถึงแอปไปยังไฟล์ proc xt_qtaguid เหล่านั้นจะถูกบล็อกโดยสิ้นเชิง เราจะเริ่มลบโมดูล xt_qtaguid ออกจากเคอร์เนลทั่วไปใหม่ของ Android หลังจากลบออกแล้ว เราจะอัปเดตการกำหนดค่าพื้นฐานของ Android สำหรับเวอร์ชันเคอร์เนลนั้นเพื่อปิดโมดูล xt_qtaguid อย่างชัดเจน โมดูล xt_qtaguid จะเลิกใช้โดยสิ้นเชิงเมื่อข้อกำหนดเวอร์ชันเคอร์เนลขั้นต่ำสำหรับรุ่น Android คือ 4.9 หรือสูงกว่า

ในรุ่น Android 9 เฉพาะอุปกรณ์ที่เปิดตัวพร้อมกับรุ่น Android 9 เท่านั้นที่จำเป็นต้องมีคุณสมบัติ eBPF ใหม่ สำหรับอุปกรณ์ที่มาพร้อมกับเคอร์เนลที่สามารถรองรับเครื่องมือ eBPF เราขอแนะนำให้อัปเดตเป็นคุณสมบัติ eBPF ใหม่เมื่ออัปเกรดเป็น Android 9 รุ่น ไม่มีการทดสอบ CTS เพื่อบังคับใช้การอัปเดตนั้น

การตรวจสอบ

คุณควรรับแพตช์จากเคอร์เนลทั่วไปของ Android และ Android AOSP หลักเป็นประจำ ตรวจสอบให้แน่ใจว่าการใช้งานของคุณผ่านการทดสอบ VTS และ CTS ที่เกี่ยวข้อง, netd_unit_test และ libbpf_test

การทดสอบ

มี เคอร์เนล net_tests เพื่อให้แน่ใจว่าคุณได้เปิดคุณสมบัติที่จำเป็นและแพตช์เคอร์เนลที่จำเป็นในแบ็คพอร์ต การทดสอบดังกล่าวรวมอยู่ในการทดสอบ 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 อยู่ที่:

การทดสอบ VTS อยู่ที่ https://android.googlesource.com/kernel/tests/+/main/net/test/bpf_test.py

การทดสอบหน่วยอยู่ที่: