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