Giám sát lưu lượng truy cập eBPF

Công cụ lưu lượng truy cập mạng eBPF sử dụng kết hợp việc triển khai hạt nhân và không gian người dùng để theo dõi mức sử dụng mạng trên thiết bị kể từ lần khởi động thiết bị gần đây nhất. API này cung cấp chức năng bổ sung như gắn thẻ với cổng, phân tách lưu lượng truy cập ở nền trước/nền và tường lửa theo UID để chặn ứng dụng truy cập mạng tuỳ thuộc vào trạng thái của điện thoại. Số liệu thống kê thu thập được từ công cụ này được lưu trữ trong một cấu trúc dữ liệu hạt nhân có tên là eBPF maps và kết quả được các dịch vụ như NetworkStatsService sử dụng để cung cấp số liệu thống kê lưu lượng truy cập liên tục kể từ lần khởi động gần đây nhất.

Ví dụ và nguồn

Các thay đổi về không gian người dùng chủ yếu nằm trong dự án system/netdframework/base. Quá trình phát triển đang được thực hiện trong AOSP, vì vậy, mã AOSP sẽ luôn được cập nhật. Nguồn này chủ yếu nằm ở system/netd/server/TrafficController*, system/netd/bpfloadersystem/netd/libbpf/. Một số thay đổi cần thiết về khung cũng có trong framework/base/system/core.

Triển khai

Kể từ Android 9, các thiết bị Android chạy trên hạt nhân 4.9 trở lên và ban đầu được vận chuyển bằng bản phát hành P PHẢI sử dụng tính năng kế toán giám sát lưu lượng truy cập mạng dựa trên eBPF thay vì xt_qtaguid. Cơ sở hạ tầng mới linh hoạt hơn và dễ bảo trì hơn, đồng thời không yêu cầu bất kỳ mã hạt nhân ngoài cây nào.

Hình 1 minh hoạ những điểm khác biệt chính về thiết kế giữa tính năng giám sát lưu lượng truy cập cũ và eBPF.

Sự khác biệt về thiết kế giám sát lưu lượng truy cập cũ và eBPF

Hình 1. Sự khác biệt về thiết kế giám sát lưu lượng truy cập cũ (bên trái) và eBPF (bên phải)

Thiết kế trafficController mới dựa trên bộ lọc eBPF trên mỗi cgroup cũng như mô-đun netfilter xt_bpf bên trong hạt nhân. Các bộ lọc eBPF này được áp dụng cho gói tx/rx khi chúng đi qua bộ lọc. Bộ lọc eBPF cgroup nằm ở lớp truyền tải và chịu trách nhiệm đếm lưu lượng truy cập theo UID phù hợp, tuỳ thuộc vào UID ổ cắm cũng như chế độ cài đặt không gian người dùng. Bộ lọc netfilter xt_bpf được nối vào chuỗi bw_raw_PREROUTINGbw_mangle_POSTROUTING, đồng thời chịu trách nhiệm đếm lưu lượng truy cập trên giao diện chính xác.

Tại thời điểm khởi động, quy trình không gian người dùng trafficController sẽ tạo các bản đồ eBPF dùng để thu thập dữ liệu và ghim tất cả các bản đồ dưới dạng một tệp ảo tại sys/fs/bpf. Sau đó, quy trình đặc quyền bpfloader sẽ tải chương trình eBPF được biên dịch trước vào hạt nhân và đính kèm chương trình đó vào cgroup chính xác. Có một cgroup gốc duy nhất cho mọi lưu lượng truy cập, vì vậy, tất cả quy trình phải được đưa vào cgroup đó theo mặc định.

Trong thời gian chạy, trafficController có thể gắn thẻ/bỏ gắn thẻ một ổ cắm bằng cách ghi vào traffic_cookie_tag_maptraffic_uid_counterSet_map. NetworkStatsService có thể đọc dữ liệu thống kê lưu lượng truy cập từ traffic_tag_stats_map, traffic_uid_stats_maptraffic_iface_stats_map. Ngoài hàm thu thập số liệu thống kê về lưu lượng truy cập, bộ lọc eBPF trafficControllercgroup cũng chịu trách nhiệm chặn lưu lượng truy cập từ một số UID nhất định tuỳ thuộc vào chế độ cài đặt điện thoại. Tính năng chặn lưu lượng truy cập mạng dựa trên UID là tính năng thay thế mô-đun xt_owner bên trong hạt nhân và bạn có thể định cấu hình chế độ chi tiết bằng cách ghi vào traffic_powersave_uid_map, traffic_standby_uid_maptraffic_dozable_uid_map.

Cách triển khai mới tuân theo cách triển khai mô-đun xt_qtaguid cũ, vì vậy, TrafficControllerNetworkStatsService sẽ chạy bằng cách triển khai cũ hoặc mới. Nếu sử dụng API công khai, ứng dụng sẽ không gặp bất kỳ sự khác biệt nào khi sử dụng công cụ xt_qtaguid hoặc eBPF ở chế độ nền.

Nếu nhân của thiết bị dựa trên nhân hệ điều hành Android phổ biến 4.9 (SHA 39c856663dcc81739e52b02b77d6af259eb838f6 trở lên), thì bạn không cần sửa đổi HAL, trình điều khiển hoặc mã nhân để triển khai công cụ eBPF mới.

Yêu cầu

  1. Cấu hình hạt nhân PHẢI bật các cấu hình sau:

    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

    Kiểm thử cấu hình hạt nhân VTS sẽ hữu ích khi xác minh rằng bạn đã bật đúng cấu hình.

Quy trình ngừng sử dụng xt_qtaguid cũ

Công cụ eBPF mới sẽ thay thế mô-đun xt_qtaguid và mô-đun xt_owner dựa trên mô-đun này. Chúng ta sẽ bắt đầu xoá mô-đun xt_qtaguid khỏi hạt nhân Android và tắt các cấu hình không cần thiết của mô-đun đó.

Trong bản phát hành Android 9, mô-đun xt_qtaguid được bật trong tất cả thiết bị, nhưng tất cả API công khai trực tiếp đọc tệp proc mô-đun xt_qtaguid đều được chuyển vào Dịch vụ NetworkManagement. Tuỳ thuộc vào phiên bản hạt nhân thiết bị và cấp độ API đầu tiên, Dịch vụ NetworkManagement sẽ biết liệu các công cụ eBPF có được bật hay không và chọn mô-đun phù hợp để lấy cho mỗi số liệu thống kê về mức sử dụng mạng của ứng dụng. Các ứng dụng có SDK cấp 28 trở lên sẽ bị sepolicy chặn truy cập vào tệp proc xt_qtaguid.

Trong bản phát hành Android tiếp theo sau Android 9, quyền truy cập của ứng dụng vào các tệp proc xt_qtaguid đó sẽ bị chặn hoàn toàn. Chúng tôi sẽ bắt đầu xoá mô-đun xt_qtaguid khỏi các hạt nhân phổ biến mới của Android. Sau khi xoá, chúng tôi sẽ cập nhật cấu hình cơ sở Android cho phiên bản nhân đó để tắt mô-đun xt_qtaguid một cách rõ ràng. Mô-đun xt_qtaguid sẽ không được dùng nữa khi yêu cầu phiên bản nhân tối thiểu cho bản phát hành Android là 4.9 trở lên.

Trong bản phát hành Android 9, chỉ những thiết bị chạy bằng bản phát hành Android 9 mới bắt buộc phải có tính năng eBPF mới. Đối với các thiết bị được vận chuyển với hạt nhân có thể hỗ trợ các công cụ eBPF, bạn nên cập nhật hạt nhân đó lên tính năng eBPF mới khi nâng cấp lên bản phát hành Android 9. Không có quy trình kiểm thử CTS nào để thực thi bản cập nhật đó.

Xác nhận kết quả

Bạn nên thường xuyên lấy các bản vá từ hạt nhân Android phổ biến và hạt nhân chính Android AOSP. Đảm bảo quá trình triển khai của bạn vượt qua các bài kiểm thử VTS và CTS hiện hành, netd_unit_testlibbpf_test.

Thử nghiệm

kernel net_tests để đảm bảo bạn đã bật các tính năng bắt buộc và các bản vá hạt nhân bắt buộc đã được điều chỉnh cho phiên bản cũ. Các chương trình kiểm thử này được tích hợp trong các chương trình kiểm thử VTS của bản phát hành Android 9. Có một số kiểm thử đơn vị trong system/netd/ (netd_unit_testlibbpf_test). Có một số kiểm thử trong netd_integration_test để xác thực hành vi tổng thể của công cụ mới.

Trình xác minh CTS và CTS

Vì cả hai mô-đun giám sát lưu lượng truy cập đều được hỗ trợ trong bản phát hành Android 9, nên không có chương trình kiểm thử CTS nào để buộc triển khai mô-đun mới trên tất cả thiết bị. Tuy nhiên, đối với các thiết bị có phiên bản nhân cao hơn 4.9 ban đầu đi kèm với bản phát hành Android 9 (tức là cấp độ API đầu tiên >= 28), có các kiểm thử CTS trên GSI để xác thực rằng mô-đun mới được định cấu hình chính xác. Bạn có thể sử dụng các chương trình kiểm thử CTS cũ như TrafficStatsTest, NetworkUsageStatsTestCtsNativeNetTestCases để xác minh hành vi cho nhất quán với mô-đun UID cũ.

Kiểm thử theo cách thủ công

Có một số kiểm thử đơn vị trong system/netd/ (netd_unit_test, netd_integration_testlibbpf_test). Dumpsys hỗ trợ kiểm tra trạng thái theo cách thủ công. Lệnh dumpsys netd cho biết trạng thái cơ bản của mô-đun trafficController và liệu eBPF có được bật chính xác hay không. Nếu eBPF được bật, lệnh dumpsys netd trafficcontroller sẽ hiển thị nội dung chi tiết của từng bản đồ eBPF, bao gồm cả thông tin về ổ cắm được gắn thẻ, số liệu thống kê theo thẻ, UID và giao diện người dùng, cũng như thông tin trùng khớp với UID của chủ sở hữu.

Vị trí kiểm thử

Các bài kiểm tra CTS được đặt tại:

Các bài kiểm thử VTS nằm tại https://android.googlesource.com/kernel/tests/+/main/net/test/bpf_test.py.

Các bài kiểm thử đơn vị nằm ở: