• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.networkstack.tethering;
17 
18 import static android.system.OsConstants.ETH_P_IP;
19 import static android.system.OsConstants.ETH_P_IPV6;
20 
21 import static com.android.networkstack.tethering.util.TetheringUtils.getTetheringJniLibraryName;
22 
23 import androidx.annotation.NonNull;
24 
25 import com.android.net.module.util.InterfaceParams;
26 import com.android.net.module.util.TcUtils;
27 
28 import java.io.IOException;
29 
30 /**
31  * The classes and the methods for BPF utilization.
32  *
33  * {@hide}
34  */
35 public class BpfUtils {
36     static {
getTetheringJniLibraryName()37         System.loadLibrary(getTetheringJniLibraryName());
38     }
39 
40     // For better code clarity when used for 'bool ingress' parameter.
41     static final boolean EGRESS = false;
42     static final boolean INGRESS = true;
43 
44     // For better code clarify when used for 'bool downstream' parameter.
45     //
46     // This is talking about the direction of travel of the offloaded packets.
47     //
48     // Upstream means packets heading towards the internet/uplink (upload),
49     // thus for tethering this is attached to ingress on the downstream interface,
50     // while for clat this is attached to egress on the v4-* clat interface.
51     //
52     // Downstream means packets coming from the internet/uplink (download), thus
53     // for both clat and tethering this is attached to ingress on the upstream interface.
54     static final boolean DOWNSTREAM = true;
55     static final boolean UPSTREAM = false;
56 
57     // The priority of tether hooks - smaller is higher priority.
58     // TC tether is higher priority then TC clat to match XDP winning over TC.
59     // Sync from system/netd/server/TcUtils.h.
60     static final short PRIO_TETHER6 = 2;
61     static final short PRIO_TETHER4 = 3;
62     // note that the above must be lower than PRIO_CLAT from netd's OffloadUtils.cpp
63 
makeProgPath(boolean downstream, int ipVersion, boolean ether)64     private static String makeProgPath(boolean downstream, int ipVersion, boolean ether) {
65         String path = "/sys/fs/bpf/tethering/prog_offload_schedcls_tether_"
66                 + (downstream ? "downstream" : "upstream")
67                 + ipVersion + "_"
68                 + (ether ? "ether" : "rawip");
69         return path;
70     }
71 
72     /**
73      * Attach BPF program
74      *
75      * TODO: use interface index to replace interface name.
76      */
attachProgram(@onNull String iface, boolean downstream)77     public static void attachProgram(@NonNull String iface, boolean downstream)
78             throws IOException {
79         final InterfaceParams params = InterfaceParams.getByName(iface);
80         if (params == null) {
81             throw new IOException("Fail to get interface params for interface " + iface);
82         }
83 
84         boolean ether;
85         try {
86             ether = TcUtils.isEthernet(iface);
87         } catch (IOException e) {
88             throw new IOException("isEthernet(" + params.index + "[" + iface + "]) failure: " + e);
89         }
90 
91         try {
92             // tc filter add dev .. ingress prio 1 protocol ipv6 bpf object-pinned /sys/fs/bpf/...
93             // direct-action
94             TcUtils.tcFilterAddDevBpf(params.index, INGRESS, PRIO_TETHER6, (short) ETH_P_IPV6,
95                     makeProgPath(downstream, 6, ether));
96         } catch (IOException e) {
97             throw new IOException("tc filter add dev (" + params.index + "[" + iface
98                     + "]) ingress prio PRIO_TETHER6 protocol ipv6 failure: " + e);
99         }
100 
101         try {
102             // tc filter add dev .. ingress prio 2 protocol ip bpf object-pinned /sys/fs/bpf/...
103             // direct-action
104             TcUtils.tcFilterAddDevBpf(params.index, INGRESS, PRIO_TETHER4, (short) ETH_P_IP,
105                     makeProgPath(downstream, 4, ether));
106         } catch (IOException e) {
107             throw new IOException("tc filter add dev (" + params.index + "[" + iface
108                     + "]) ingress prio PRIO_TETHER4 protocol ip failure: " + e);
109         }
110     }
111 
112     /**
113      * Detach BPF program
114      *
115      * TODO: use interface index to replace interface name.
116      */
detachProgram(@onNull String iface)117     public static void detachProgram(@NonNull String iface) throws IOException {
118         final InterfaceParams params = InterfaceParams.getByName(iface);
119         if (params == null) {
120             throw new IOException("Fail to get interface params for interface " + iface);
121         }
122 
123         try {
124             // tc filter del dev .. ingress prio 1 protocol ipv6
125             TcUtils.tcFilterDelDev(params.index, INGRESS, PRIO_TETHER6, (short) ETH_P_IPV6);
126         } catch (IOException e) {
127             throw new IOException("tc filter del dev (" + params.index + "[" + iface
128                     + "]) ingress prio PRIO_TETHER6 protocol ipv6 failure: " + e);
129         }
130 
131         try {
132             // tc filter del dev .. ingress prio 2 protocol ip
133             TcUtils.tcFilterDelDev(params.index, INGRESS, PRIO_TETHER4, (short) ETH_P_IP);
134         } catch (IOException e) {
135             throw new IOException("tc filter del dev (" + params.index + "[" + iface
136                     + "]) ingress prio PRIO_TETHER4 protocol ip failure: " + e);
137         }
138     }
139 }
140