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 sự kết hợp giữa việc triển khai không gian người dùng và nhân để 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. Nó cung cấp thêm chức năng như gắn thẻ ổ cắm, tách lưu lượng truy cập ở nền trước/nền sau và tường lửa theo UID để chặn các ứng dụng truy cập vào mạng tuỳ thuộc vào trạng thái đ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 của 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 các 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 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 nằm trong framework/base/system/core.

Triển khai

Kể từ Android 9, các thiết bị Android chạy trên nhân 4.9 trở lên và ban đầu được phát hành cùng với 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 và dễ duy trì hơn, đồng thời không yêu cầu bất kỳ mã hạt nhân nào ngoài cây.

Sự 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 được minh hoạ trong Hình 1.

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

Hình 1. Sự khác biệt giữa 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 cũng dựa trên bộ lọc eBPF cgroup cho mỗi bộ lọc cũng như mô-đun xt_bpf netfilter bên trong nhân. Các bộ lọc eBPF này được áp dụng trên tx/rx gói khi chúng đi qua bộ lọc. Bộ lọc cgroup eBPF 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ủa ổ cắm cũng như chế độ cài đặt không gian người dùng. xt_bpf netfilter được kết nối tại chuỗi bw_raw_PREROUTINGbw_mangle_POSTROUTING, đồng thời chịu trách nhiệm đếm lưu lượng truy cập đối với 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 được 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 tất cả lưu lượng truy cập, vì vậy, theo mặc định, tất cả quy trình đều phải có trong cgroup đó.

Trong thời gian chạy, trafficController có thể gắn/huỷ 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 chức năng thu thập số liệu thống kê về lưu lượng truy cập, bộ lọc trafficControllercgroup eBPF 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à một tính năng thay thế cho mô-đun xt_owner bên trong 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.

Quy trình triển khai mới tuân theo quy trình triển khai mô-đun xt_qtaguid cũ, do đó, TrafficControllerNetworkStatsService sẽ chạy với quy trình triển khai cũ hoặc mới. Nếu sử dụng các API công khai, ứng dụng sẽ không gặp phải bất kỳ sự khác biệt nào cho dù xt_qtaguid hay các công cụ eBPF được dùng trong nền.

Nếu nhân thiết bị dựa trên nhân chung Android 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 kernel 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 rất 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 đang thay thế mô-đun xt_qtaguid và mô-đun xt_owner mà công cụ này dựa trên. Chúng tôi sẽ bắt đầu xoá mô-đun xt_qtaguid khỏi nhân Android và tắt các cấu hình không cần thiết của mô-đun này.

Trong bản phát hành Android 9, mô-đun xt_qtaguid sẽ được bật trên tất cả các thiết bị, nhưng tất cả cá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 nhân của 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 để nhận cho từng 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 các tệp proc xt_qtaguid.

Trong bản phát hành Android tiếp theo sau phiên bản 9, quyền truy cập của ứng dụng vào các tệp xt_qtaguid proc đó sẽ bị chặn hoàn toàn và chúng tôi sẽ bắt đầu xoá mô-đun xt_qtaguid khỏi các nhân chung mới của Android. Sau khi xoá, chúng tôi sẽ cập nhật cấu hình cơ sở của Android cho phiên bản nhân đó để tắt rõ ràng mô-đun xt_qtaguid. Mô-đun xt_qtaguid sẽ hoàn toàn không được dùng nữa khi yêu cầu về phiên bản nhân tối thiểu cho một 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ị ra mắt cùng với 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 những thiết bị được xuất xưởng cùng với một nhân có thể hỗ trợ các công cụ eBPF, bạn nên cập nhậ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ó 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ừ các hạt nhân chung của Android và Android AOSP main. Đảm bảo chế độ triển khai của bạn vượt qua các 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á kernel bắt buộc đã được chuyển ngược. Các kiểm thử này được tích hợp trong các 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.

CTS và trình xác minh 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ó kiểm thử CTS nào bắt buộc triển khai mô-đun mới trên tất cả cá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 và ban đầu được phát hành cùng 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ể dùng các bài kiểm thử CTS cũ như TrafficStatsTest, NetworkUsageStatsTestCtsNativeNetTestCases để xác minh hành vi 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). Có hỗ trợ dumpsys để 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 đúng cách hay không. Nếu eBPF được bật, lệnh dumpsys netd trafficcontroller sẽ cho thấy nội dung chi tiết của từng bản đồ eBPF, bao gồm thông tin về socket được gắn thẻ, số liệu thống kê cho mỗi thẻ, UID và iface, cũng như thông tin trùng khớp về UID của chủ sở hữu.

Vị trí kiểm thử

Các bài kiểm thử CTS nằm ở:

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

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