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