1 /*
2  * Copyright (C) 2020 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 
17 package com.android.networkstack.tethering.apishim.common;
18 
19 import android.util.SparseArray;
20 
21 import androidx.annotation.NonNull;
22 import androidx.annotation.Nullable;
23 
24 import com.android.net.module.util.IBpfMap.ThrowingBiConsumer;
25 import com.android.net.module.util.bpf.Tether4Key;
26 import com.android.net.module.util.bpf.Tether4Value;
27 import com.android.net.module.util.bpf.TetherStatsValue;
28 import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
29 import com.android.networkstack.tethering.BpfCoordinator.Ipv6DownstreamRule;
30 import com.android.networkstack.tethering.BpfCoordinator.Ipv6UpstreamRule;
31 
32 /**
33  * Bpf coordinator class for API shims.
34  */
35 public abstract class BpfCoordinatorShim {
36     /**
37      * Get BpfCoordinatorShim object by OS build version.
38      */
39     @NonNull
getBpfCoordinatorShim(@onNull final Dependencies deps)40     public static BpfCoordinatorShim getBpfCoordinatorShim(@NonNull final Dependencies deps) {
41         if (deps.isAtLeastS()) {
42             return new com.android.networkstack.tethering.apishim.api31.BpfCoordinatorShimImpl(
43                     deps);
44         } else {
45             return new com.android.networkstack.tethering.apishim.api30.BpfCoordinatorShimImpl(
46                     deps);
47         }
48     }
49 
50     /**
51      * Return true if this class has been initialized, otherwise return false.
52      */
isInitialized()53     public abstract boolean isInitialized();
54 
55     /**
56      * Adds a tethering offload upstream rule to BPF map, or updates it if it already exists.
57      *
58      * An existing rule will be updated if the input interface, destination MAC and source prefix
59      * match. Otherwise, a new rule will be created. Note that this can be only called on handler
60      * thread.
61      *
62      * @param rule The rule to add or update.
63      * @return true if operation succeeded or was a no-op, false otherwise.
64      */
addIpv6UpstreamRule(@onNull Ipv6UpstreamRule rule)65     public abstract boolean addIpv6UpstreamRule(@NonNull Ipv6UpstreamRule rule);
66 
67     /**
68      * Deletes a tethering offload upstream rule from the BPF map.
69      *
70      * An existing rule will be deleted if the input interface, destination MAC and source prefix
71      * match. It is not an error if there is no matching rule to delete.
72      *
73      * @param rule The rule to delete.
74      * @return true if operation succeeded or was a no-op, false otherwise.
75      */
removeIpv6UpstreamRule(@onNull Ipv6UpstreamRule rule)76     public abstract boolean removeIpv6UpstreamRule(@NonNull Ipv6UpstreamRule rule);
77 
78     /**
79      * Adds a tethering offload downstream rule to BPF map, or updates it if it already exists.
80      *
81      * Currently, only downstream /128 IPv6 entries are supported. An existing rule will be updated
82      * if the input interface and destination prefix match. Otherwise, a new rule will be created.
83      * Note that this can be only called on handler thread.
84      *
85      * @param rule The rule to add or update.
86      * @return true if operation succeeded or was a no-op, false otherwise.
87      */
addIpv6DownstreamRule(@onNull Ipv6DownstreamRule rule)88     public abstract boolean addIpv6DownstreamRule(@NonNull Ipv6DownstreamRule rule);
89 
90     /**
91      * Deletes a tethering offload downstream rule from the BPF map.
92      *
93      * Currently, only downstream /128 IPv6 entries are supported. An existing rule will be deleted
94      * if the destination IP address and the source interface match. It is not an error if there is
95      * no matching rule to delete.
96      *
97      * @param rule The rule to delete.
98      * @return true if operation succeeded or was a no-op, false otherwise.
99      */
removeIpv6DownstreamRule(@onNull Ipv6DownstreamRule rule)100     public abstract boolean removeIpv6DownstreamRule(@NonNull Ipv6DownstreamRule rule);
101 
102     /**
103      * Return BPF tethering offload statistics.
104      *
105      * @return an array of TetherStatsValue's, where each entry contains the upstream interface
106      *         index and its tethering statistics since tethering was first started.
107      *         There will only ever be one entry for a given interface index.
108      */
109     @Nullable
tetherOffloadGetStats()110     public abstract SparseArray<TetherStatsValue> tetherOffloadGetStats();
111 
112    /**
113     * Set a per-interface quota for tethering offload.
114     *
115     * @param ifIndex Index of upstream interface
116     * @param quotaBytes The quota defined as the number of bytes, starting from zero and counting
117     *       from *now*. A value of QUOTA_UNLIMITED (-1) indicates there is no limit.
118     */
119     @Nullable
tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes)120     public abstract boolean tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes);
121 
122     /**
123      * Return BPF tethering offload statistics and clear the stats for a given upstream.
124      *
125      * Must only be called once all offload rules have already been deleted for the given upstream
126      * interface. The existing stats will be fetched and returned. The stats and the limit for the
127      * given upstream interface will be deleted as well.
128      *
129      * The stats and limit for a given upstream interface must be initialized (using
130      * tetherOffloadSetInterfaceQuota) before any offload will occur on that interface.
131      *
132      * Note that this can be only called while the BPF maps were initialized.
133      *
134      * @param ifIndex Index of upstream interface.
135      * @return TetherStatsValue, which contains the given upstream interface's tethering statistics
136      *         since tethering was first started on that upstream interface.
137      */
138     @Nullable
tetherOffloadGetAndClearStats(int ifIndex)139     public abstract TetherStatsValue tetherOffloadGetAndClearStats(int ifIndex);
140 
141     /**
142      * Adds a tethering IPv4 offload rule to appropriate BPF map.
143      */
tetherOffloadRuleAdd(boolean downstream, @NonNull Tether4Key key, @NonNull Tether4Value value)144     public abstract boolean tetherOffloadRuleAdd(boolean downstream, @NonNull Tether4Key key,
145             @NonNull Tether4Value value);
146 
147     /**
148      * Deletes a tethering IPv4 offload rule from the appropriate BPF map.
149      *
150      * @param downstream true if downstream, false if upstream.
151      * @param key the key to delete.
152      * @return true iff the map was modified, false if the key did not exist or there was an error.
153      */
tetherOffloadRuleRemove(boolean downstream, @NonNull Tether4Key key)154     public abstract boolean tetherOffloadRuleRemove(boolean downstream, @NonNull Tether4Key key);
155 
156     /**
157      * Iterate through the map and handle each key -> value retrieved base on the given BiConsumer.
158      *
159      * @param downstream true if downstream, false if upstream.
160      * @param action represents the action for each key -> value. The entry deletion is not
161      *        allowed and use #tetherOffloadRuleRemove instead.
162      */
163     @Nullable
tetherOffloadRuleForEach(boolean downstream, @NonNull ThrowingBiConsumer<Tether4Key, Tether4Value> action)164     public abstract void tetherOffloadRuleForEach(boolean downstream,
165             @NonNull ThrowingBiConsumer<Tether4Key, Tether4Value> action);
166 
167     /**
168      * Whether there is currently any IPv4 rule on the specified upstream.
169      */
isAnyIpv4RuleOnUpstream(int ifIndex)170     public abstract boolean isAnyIpv4RuleOnUpstream(int ifIndex);
171 
172     /**
173      * Attach BPF program.
174      *
175      * @param iface the interface name to attach program.
176      * @param downstream indicate the datapath. true if downstream, false if upstream.
177      * @param ipv4 indicate the protocol family. true if ipv4, false if ipv6.
178      *
179      * TODO: consider using InterfaceParams to replace interface name.
180      */
attachProgram(@onNull String iface, boolean downstream, boolean ipv4)181     public abstract boolean attachProgram(@NonNull String iface, boolean downstream,
182             boolean ipv4);
183 
184     /**
185      * Detach BPF program.
186      *
187      * @param iface the interface name to detach program.
188      * @param ipv4 indicate the protocol family. true if ipv4, false if ipv6.
189      *
190      * TODO: consider using InterfaceParams to replace interface name.
191      */
detachProgram(@onNull String iface, boolean ipv4)192     public abstract boolean detachProgram(@NonNull String iface, boolean ipv4);
193 
194     /**
195      * Add interface index mapping.
196      */
addDevMap(int ifIndex)197     public abstract boolean addDevMap(int ifIndex);
198 
199     /**
200      * Remove interface index mapping.
201      */
removeDevMap(int ifIndex)202     public abstract boolean removeDevMap(int ifIndex);
203 }
204 
205