• 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 android.net.util.InterfaceParams;
22 
23 import androidx.annotation.NonNull;
24 
25 import java.io.IOException;
26 
27 /**
28  * The classes and the methods for BPF utilization.
29  *
30  * {@hide}
31  */
32 public class BpfUtils {
33     static {
34         System.loadLibrary("tetherutilsjni");
35     }
36 
37     // For better code clarity when used for 'bool ingress' parameter.
38     static final boolean EGRESS = false;
39     static final boolean INGRESS = true;
40 
41     // For better code clarify when used for 'bool downstream' parameter.
42     //
43     // This is talking about the direction of travel of the offloaded packets.
44     //
45     // Upstream means packets heading towards the internet/uplink (upload),
46     // thus for tethering this is attached to ingress on the downstream interface,
47     // while for clat this is attached to egress on the v4-* clat interface.
48     //
49     // Downstream means packets coming from the internet/uplink (download), thus
50     // for both clat and tethering this is attached to ingress on the upstream interface.
51     static final boolean DOWNSTREAM = true;
52     static final boolean UPSTREAM = false;
53 
54     // The priority of clat/tether hooks - smaller is higher priority.
55     // TC tether is higher priority then TC clat to match XDP winning over TC.
56     // Sync from system/netd/server/OffloadUtils.h.
57     static final short PRIO_TETHER6 = 1;
58     static final short PRIO_TETHER4 = 2;
59     // note that the above must be lower than PRIO_CLAT from netd's OffloadUtils.cpp
60 
makeProgPath(boolean downstream, int ipVersion, boolean ether)61     private static String makeProgPath(boolean downstream, int ipVersion, boolean ether) {
62         String path = "/sys/fs/bpf/tethering/prog_offload_schedcls_tether_"
63                 + (downstream ? "downstream" : "upstream")
64                 + ipVersion + "_"
65                 + (ether ? "ether" : "rawip");
66         return path;
67     }
68 
69     /**
70      * Attach BPF program
71      *
72      * TODO: use interface index to replace interface name.
73      */
attachProgram(@onNull String iface, boolean downstream)74     public static void attachProgram(@NonNull String iface, boolean downstream)
75             throws IOException {
76         final InterfaceParams params = InterfaceParams.getByName(iface);
77         if (params == null) {
78             throw new IOException("Fail to get interface params for interface " + iface);
79         }
80 
81         boolean ether;
82         try {
83             ether = isEthernet(iface);
84         } catch (IOException e) {
85             throw new IOException("isEthernet(" + params.index + "[" + iface + "]) failure: " + e);
86         }
87 
88         try {
89             // tc filter add dev .. ingress prio 1 protocol ipv6 bpf object-pinned /sys/fs/bpf/...
90             // direct-action
91             tcFilterAddDevBpf(params.index, INGRESS, PRIO_TETHER6, (short) ETH_P_IPV6,
92                     makeProgPath(downstream, 6, ether));
93         } catch (IOException e) {
94             throw new IOException("tc filter add dev (" + params.index + "[" + iface
95                     + "]) ingress prio PRIO_TETHER6 protocol ipv6 failure: " + e);
96         }
97 
98         try {
99             // tc filter add dev .. ingress prio 2 protocol ip bpf object-pinned /sys/fs/bpf/...
100             // direct-action
101             tcFilterAddDevBpf(params.index, INGRESS, PRIO_TETHER4, (short) ETH_P_IP,
102                     makeProgPath(downstream, 4, ether));
103         } catch (IOException e) {
104             throw new IOException("tc filter add dev (" + params.index + "[" + iface
105                     + "]) ingress prio PRIO_TETHER4 protocol ip failure: " + e);
106         }
107     }
108 
109     /**
110      * Detach BPF program
111      *
112      * TODO: use interface index to replace interface name.
113      */
detachProgram(@onNull String iface)114     public static void detachProgram(@NonNull String iface) throws IOException {
115         final InterfaceParams params = InterfaceParams.getByName(iface);
116         if (params == null) {
117             throw new IOException("Fail to get interface params for interface " + iface);
118         }
119 
120         try {
121             // tc filter del dev .. ingress prio 1 protocol ipv6
122             tcFilterDelDev(params.index, INGRESS, PRIO_TETHER6, (short) ETH_P_IPV6);
123         } catch (IOException e) {
124             throw new IOException("tc filter del dev (" + params.index + "[" + iface
125                     + "]) ingress prio PRIO_TETHER6 protocol ipv6 failure: " + e);
126         }
127 
128         try {
129             // tc filter del dev .. ingress prio 2 protocol ip
130             tcFilterDelDev(params.index, INGRESS, PRIO_TETHER4, (short) ETH_P_IP);
131         } catch (IOException e) {
132             throw new IOException("tc filter del dev (" + params.index + "[" + iface
133                     + "]) ingress prio PRIO_TETHER4 protocol ip failure: " + e);
134         }
135     }
136 
isEthernet(String iface)137     private static native boolean isEthernet(String iface) throws IOException;
138 
tcFilterAddDevBpf(int ifIndex, boolean ingress, short prio, short proto, String bpfProgPath)139     private static native void tcFilterAddDevBpf(int ifIndex, boolean ingress, short prio,
140             short proto, String bpfProgPath) throws IOException;
141 
tcFilterDelDev(int ifIndex, boolean ingress, short prio, short proto)142     private static native void tcFilterDelDev(int ifIndex, boolean ingress, short prio,
143             short proto) throws IOException;
144 }
145