การตรวจสอบการจราจร 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. ความแตกต่างของการออกแบบการตรวจสอบการรับส่งข้อมูลแบบ 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 ใหม่

ความต้องการ

  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 มีประโยชน์เมื่อตรวจสอบว่าการกำหนดค่าที่ถูกต้องเปิดอยู่

  2. อุปกรณ์ 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 ตั้งอยู่ที่:

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

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