Merge changes I8cd6e49b,Ibb52c7b7 am: dc4189f0e4 am: 3b0f7f1d6e am: 4158939871

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/1557658

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Ifad6ded6097c458cc1b5dba9d167c5920ff2c180
This commit is contained in:
Lorenzo Colitti
2021-01-26 02:14:37 +00:00
committed by Automerger Merge Worker
10 changed files with 660 additions and 5 deletions

View File

@@ -28,7 +28,11 @@ import androidx.annotation.Nullable;
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
import com.android.networkstack.tethering.TetherDownstream4Key;
import com.android.networkstack.tethering.TetherDownstream4Value;
import com.android.networkstack.tethering.TetherStatsValue;
import com.android.networkstack.tethering.TetherUpstream4Key;
import com.android.networkstack.tethering.TetherUpstream4Value;
/**
* Bpf coordinator class for API shims.
@@ -131,6 +135,32 @@ public class BpfCoordinatorShimImpl
}
}
@Override
public boolean tetherOffloadRuleAdd(@NonNull TetherDownstream4Key key,
@NonNull TetherDownstream4Value value) {
/* no op */
return true;
}
@Override
public boolean tetherOffloadRuleRemove(@NonNull TetherDownstream4Key key) {
/* no op */
return true;
}
@Override
public boolean tetherOffloadRuleAdd(@NonNull TetherUpstream4Key key,
@NonNull TetherUpstream4Value value) {
/* no op */
return true;
}
@Override
public boolean tetherOffloadRuleRemove(@NonNull TetherUpstream4Key key) {
/* no op */
return true;
}
@Override
public String toString() {
return "Netd used";

View File

@@ -30,12 +30,16 @@ import androidx.annotation.Nullable;
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
import com.android.networkstack.tethering.BpfMap;
import com.android.networkstack.tethering.TetherDownstream4Key;
import com.android.networkstack.tethering.TetherDownstream4Value;
import com.android.networkstack.tethering.TetherDownstream6Key;
import com.android.networkstack.tethering.TetherDownstream6Value;
import com.android.networkstack.tethering.TetherLimitKey;
import com.android.networkstack.tethering.TetherLimitValue;
import com.android.networkstack.tethering.TetherStatsKey;
import com.android.networkstack.tethering.TetherStatsValue;
import com.android.networkstack.tethering.TetherUpstream4Key;
import com.android.networkstack.tethering.TetherUpstream4Value;
import java.io.FileDescriptor;
@@ -54,6 +58,16 @@ public class BpfCoordinatorShimImpl
@NonNull
private final SharedLog mLog;
// BPF map of ingress queueing discipline which pre-processes the packets by the IPv4
// downstream rules.
@Nullable
private final BpfMap<TetherDownstream4Key, TetherDownstream4Value> mBpfDownstream4Map;
// BPF map of ingress queueing discipline which pre-processes the packets by the IPv4
// upstream rules.
@Nullable
private final BpfMap<TetherUpstream4Key, TetherUpstream4Value> mBpfUpstream4Map;
// BPF map of ingress queueing discipline which pre-processes the packets by the IPv6
// forwarding rules.
@Nullable
@@ -69,6 +83,8 @@ public class BpfCoordinatorShimImpl
public BpfCoordinatorShimImpl(@NonNull final Dependencies deps) {
mLog = deps.getSharedLog().forSubComponent(TAG);
mBpfDownstream4Map = deps.getBpfDownstream4Map();
mBpfUpstream4Map = deps.getBpfUpstream4Map();
mBpfDownstream6Map = deps.getBpfDownstream6Map();
mBpfStatsMap = deps.getBpfStatsMap();
mBpfLimitMap = deps.getBpfLimitMap();
@@ -76,7 +92,8 @@ public class BpfCoordinatorShimImpl
@Override
public boolean isInitialized() {
return mBpfDownstream6Map != null && mBpfStatsMap != null && mBpfLimitMap != null;
return mBpfDownstream4Map != null && mBpfUpstream4Map != null && mBpfDownstream6Map != null
&& mBpfStatsMap != null && mBpfLimitMap != null;
}
@Override
@@ -232,15 +249,86 @@ public class BpfCoordinatorShimImpl
return statsValue;
}
@Override
public boolean tetherOffloadRuleAdd(@NonNull TetherDownstream4Key key,
@NonNull TetherDownstream4Value value) {
if (!isInitialized()) return false;
try {
// The last used time field of the value is updated by the bpf program. Adding the same
// map pair twice causes the unexpected refresh. Must be fixed before starting the
// conntrack timeout extension implementation.
// TODO: consider using insertEntry.
mBpfDownstream4Map.updateEntry(key, value);
} catch (ErrnoException e) {
mLog.e("Could not update entry: ", e);
return false;
}
return true;
}
@Override
public boolean tetherOffloadRuleRemove(@NonNull TetherDownstream4Key key) {
if (!isInitialized()) return false;
try {
mBpfDownstream4Map.deleteEntry(key);
} catch (ErrnoException e) {
// Silent if the rule did not exist.
if (e.errno != OsConstants.ENOENT) {
mLog.e("Could not delete entry: ", e);
return false;
}
}
return true;
}
@Override
public boolean tetherOffloadRuleAdd(@NonNull TetherUpstream4Key key,
@NonNull TetherUpstream4Value value) {
if (!isInitialized()) return false;
try {
// The last used time field of the value is updated by the bpf program. Adding the same
// map pair twice causes the unexpected refresh. Must be fixed before starting the
// conntrack timeout extension implementation.
// TODO: consider using insertEntry.
mBpfUpstream4Map.updateEntry(key, value);
} catch (ErrnoException e) {
mLog.e("Could not update entry: ", e);
return false;
}
return true;
}
@Override
public boolean tetherOffloadRuleRemove(@NonNull TetherUpstream4Key key) {
if (!isInitialized()) return false;
try {
mBpfUpstream4Map.deleteEntry(key);
} catch (ErrnoException e) {
// Silent if the rule did not exist.
if (e.errno != OsConstants.ENOENT) {
mLog.e("Could not delete entry: ", e);
return false;
}
}
return true;
}
@Override
public String toString() {
return "mBpfDownstream6Map{"
return "mBpfDownstream4Map{"
+ (mBpfDownstream4Map != null ? "initialized" : "not initialized") + "}, "
+ "mBpfUpstream4Map{"
+ (mBpfUpstream4Map != null ? "initialized" : "not initialized") + "}, "
+ "mBpfDownstream6Map{"
+ (mBpfDownstream6Map != null ? "initialized" : "not initialized") + "}, "
+ "mBpfStatsMap{"
+ (mBpfStatsMap != null ? "initialized" : "not initialized") + "}, "
+ "mBpfLimitMap{"
+ (mBpfLimitMap != null ? "initialized" : "not initialized") + "} "
+ "}";
+ (mBpfLimitMap != null ? "initialized" : "not initialized") + "} ";
}
/**

View File

@@ -23,7 +23,11 @@ import androidx.annotation.Nullable;
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
import com.android.networkstack.tethering.TetherDownstream4Key;
import com.android.networkstack.tethering.TetherDownstream4Value;
import com.android.networkstack.tethering.TetherStatsValue;
import com.android.networkstack.tethering.TetherUpstream4Key;
import com.android.networkstack.tethering.TetherUpstream4Value;
/**
* Bpf coordinator class for API shims.
@@ -108,5 +112,27 @@ public abstract class BpfCoordinatorShim {
*/
@Nullable
public abstract TetherStatsValue tetherOffloadGetAndClearStats(int ifIndex);
/**
* Adds a tethering IPv4 downstream offload rule to BPF map.
*/
public abstract boolean tetherOffloadRuleAdd(@NonNull TetherDownstream4Key key,
@NonNull TetherDownstream4Value value);
/**
* Deletes a tethering IPv4 downstream offload rule from the BPF map.
*/
public abstract boolean tetherOffloadRuleRemove(@NonNull TetherDownstream4Key key);
/**
* Adds a tethering IPv4 upstream offload rule to BPF map.
*/
public abstract boolean tetherOffloadRuleAdd(@NonNull TetherUpstream4Key key,
@NonNull TetherUpstream4Value value);
/**
* Deletes a tethering IPv4 upstream offload rule from the BPF map.
*/
public abstract boolean tetherOffloadRuleRemove(@NonNull TetherUpstream4Key key);
}

View File

@@ -23,7 +23,9 @@ import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStats.UID_TETHERING;
import static android.net.ip.ConntrackMonitor.ConntrackEvent;
import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
import static android.system.OsConstants.ETH_P_IP;
import static android.system.OsConstants.ETH_P_IPV6;
import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
@@ -38,6 +40,7 @@ import android.net.TetherOffloadRuleParcel;
import android.net.ip.ConntrackMonitor;
import android.net.ip.ConntrackMonitor.ConntrackEventConsumer;
import android.net.ip.IpServer;
import android.net.netlink.NetlinkConstants;
import android.net.netstats.provider.NetworkStatsProvider;
import android.net.util.InterfaceParams;
import android.net.util.SharedLog;
@@ -82,6 +85,12 @@ import java.util.Set;
public class BpfCoordinator {
private static final String TAG = BpfCoordinator.class.getSimpleName();
private static final int DUMP_TIMEOUT_MS = 10_000;
private static final MacAddress NULL_MAC_ADDRESS = MacAddress.fromString(
"00:00:00:00:00:00");
private static final String TETHER_DOWNSTREAM4_MAP_PATH =
"/sys/fs/bpf/tethering/map_offload_tether_downstream4_map";
private static final String TETHER_UPSTREAM4_MAP_PATH =
"/sys/fs/bpf/tethering/map_offload_tether_upstream4_map";
private static final String TETHER_DOWNSTREAM6_FS_PATH =
"/sys/fs/bpf/tethering/map_offload_tether_downstream6_map";
private static final String TETHER_STATS_MAP_PATH =
@@ -174,6 +183,9 @@ public class BpfCoordinator {
// - Must only be modified by that IpServer.
// - Is created when the IpServer adds its first client, and deleted when the IpServer deletes
// its last client.
// Note that relying on the client address for finding downstream is okay for now because the
// client address is unique. See PrivateAddressCoordinator#requestDownstreamAddress.
// TODO: Refactor if any possible that the client address is not unique.
private final HashMap<IpServer, HashMap<Inet4Address, ClientInfo>>
mTetherClients = new HashMap<>();
@@ -224,6 +236,30 @@ public class BpfCoordinator {
return SdkLevel.isAtLeastS();
}
/** Get downstream4 BPF map. */
@Nullable public BpfMap<TetherDownstream4Key, TetherDownstream4Value>
getBpfDownstream4Map() {
try {
return new BpfMap<>(TETHER_DOWNSTREAM4_MAP_PATH,
BpfMap.BPF_F_RDWR, TetherDownstream4Key.class, TetherDownstream4Value.class);
} catch (ErrnoException e) {
Log.e(TAG, "Cannot create downstream4 map: " + e);
return null;
}
}
/** Get upstream4 BPF map. */
@Nullable public BpfMap<TetherUpstream4Key, TetherUpstream4Value>
getBpfUpstream4Map() {
try {
return new BpfMap<>(TETHER_UPSTREAM4_MAP_PATH,
BpfMap.BPF_F_RDWR, TetherUpstream4Key.class, TetherUpstream4Value.class);
} catch (ErrnoException e) {
Log.e(TAG, "Cannot create upstream4 map: " + e);
return null;
}
}
/** Get downstream6 BPF map. */
@Nullable public BpfMap<TetherDownstream6Key, TetherDownstream6Value>
getBpfDownstream6Map() {
@@ -854,8 +890,97 @@ public class BpfCoordinator {
}
}
@Nullable
private ClientInfo getClientInfo(@NonNull Inet4Address clientAddress) {
for (HashMap<Inet4Address, ClientInfo> clients : mTetherClients.values()) {
for (ClientInfo client : clients.values()) {
if (clientAddress.equals(client.clientAddress)) {
return client;
}
}
}
return null;
}
// Support raw ip only.
// TODO: add ether ip support.
private class BpfConntrackEventConsumer implements ConntrackEventConsumer {
public void accept(ConntrackMonitor.ConntrackEvent e) { /* TODO */ }
@NonNull
private TetherUpstream4Key makeTetherUpstream4Key(
@NonNull ConntrackEvent e, @NonNull ClientInfo c) {
return new TetherUpstream4Key(c.downstreamIfindex, c.downstreamMac,
e.tupleOrig.protoNum, e.tupleOrig.srcIp.getAddress(),
e.tupleOrig.dstIp.getAddress(), e.tupleOrig.srcPort, e.tupleOrig.dstPort);
}
@NonNull
private TetherDownstream4Key makeTetherDownstream4Key(
@NonNull ConntrackEvent e, @NonNull ClientInfo c, int upstreamIndex) {
return new TetherDownstream4Key(upstreamIndex, NULL_MAC_ADDRESS /* dstMac (rawip) */,
e.tupleReply.protoNum, e.tupleReply.srcIp.getAddress(),
e.tupleReply.dstIp.getAddress(), e.tupleReply.srcPort, e.tupleReply.dstPort);
}
@NonNull
private TetherUpstream4Value makeTetherUpstream4Value(@NonNull ConntrackEvent e,
int upstreamIndex) {
return new TetherUpstream4Value(upstreamIndex,
NULL_MAC_ADDRESS /* ethDstMac (rawip) */,
NULL_MAC_ADDRESS /* ethSrcMac (rawip) */, ETH_P_IP,
NetworkStackConstants.ETHER_MTU, toIpv4MappedAddressBytes(e.tupleReply.dstIp),
toIpv4MappedAddressBytes(e.tupleReply.srcIp), e.tupleReply.dstPort,
e.tupleReply.srcPort, 0 /* lastUsed, filled by bpf prog only */);
}
@NonNull
private TetherDownstream4Value makeTetherDownstream4Value(@NonNull ConntrackEvent e,
@NonNull ClientInfo c, int upstreamIndex) {
return new TetherDownstream4Value(c.downstreamIfindex,
c.clientMac, c.downstreamMac, ETH_P_IP, NetworkStackConstants.ETHER_MTU,
e.tupleOrig.dstIp.getAddress(), e.tupleOrig.srcIp.getAddress(),
e.tupleOrig.dstPort, e.tupleOrig.srcPort,
0 /* lastUsed, filled by bpf prog only */);
}
@NonNull
private byte[] toIpv4MappedAddressBytes(Inet4Address ia4) {
final byte[] addr4 = ia4.getAddress();
final byte[] addr6 = new byte[16];
addr6[10] = (byte) 0xff;
addr6[11] = (byte) 0xff;
addr6[12] = addr4[0];
addr6[13] = addr4[1];
addr6[14] = addr4[2];
addr6[15] = addr4[3];
return addr6;
}
public void accept(ConntrackEvent e) {
final ClientInfo tetherClient = getClientInfo(e.tupleOrig.srcIp);
if (tetherClient == null) return;
final Integer upstreamIndex = mIpv4UpstreamIndices.get(e.tupleReply.dstIp);
if (upstreamIndex == null) return;
final TetherUpstream4Key upstream4Key = makeTetherUpstream4Key(e, tetherClient);
final TetherDownstream4Key downstream4Key = makeTetherDownstream4Key(e,
tetherClient, upstreamIndex);
if (e.msgType == (NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8
| NetlinkConstants.IPCTNL_MSG_CT_DELETE)) {
mBpfCoordinatorShim.tetherOffloadRuleRemove(upstream4Key);
mBpfCoordinatorShim.tetherOffloadRuleRemove(downstream4Key);
return;
}
final TetherUpstream4Value upstream4Value = makeTetherUpstream4Value(e,
upstreamIndex);
final TetherDownstream4Value downstream4Value = makeTetherDownstream4Value(e,
tetherClient, upstreamIndex);
mBpfCoordinatorShim.tetherOffloadRuleAdd(upstream4Key, upstream4Value);
mBpfCoordinatorShim.tetherOffloadRuleAdd(downstream4Key, downstream4Value);
}
}
private boolean isBpfEnabled() {

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.networkstack.tethering;
import android.net.MacAddress;
import com.android.net.module.util.Struct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.Objects;
/** The key of BpfMap which is used for IPv4 bpf offload. */
public class TetherDownstream4Key extends Struct {
@Field(order = 0, type = Type.U32)
public final long iif;
@Field(order = 1, type = Type.EUI48)
public final MacAddress dstMac;
@Field(order = 2, type = Type.U8, padding = 1)
public final short l4proto;
@Field(order = 3, type = Type.ByteArray, arraysize = 4)
public final byte[] src4;
@Field(order = 4, type = Type.ByteArray, arraysize = 4)
public final byte[] dst4;
@Field(order = 5, type = Type.UBE16)
public final int srcPort;
@Field(order = 6, type = Type.UBE16)
public final int dstPort;
public TetherDownstream4Key(final long iif, final MacAddress dstMac, final short l4proto,
final byte[] src4, final byte[] dst4, final int srcPort,
final int dstPort) {
Objects.requireNonNull(dstMac);
this.iif = iif;
this.dstMac = dstMac;
this.l4proto = l4proto;
this.src4 = src4;
this.dst4 = dst4;
this.srcPort = srcPort;
this.dstPort = dstPort;
}
@Override
public String toString() {
try {
return String.format(
"iif: %d, dstMac: %s, l4proto: %d, src4: %s, dst4: %s, "
+ "srcPort: %d, dstPort: %d",
iif, dstMac, l4proto,
Inet4Address.getByAddress(src4), Inet4Address.getByAddress(dst4),
Short.toUnsignedInt((short) srcPort), Short.toUnsignedInt((short) dstPort));
} catch (UnknownHostException | IllegalArgumentException e) {
return String.format("Invalid IP address", e);
}
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.networkstack.tethering;
import android.net.MacAddress;
import androidx.annotation.NonNull;
import com.android.net.module.util.Struct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Objects;
/** The value of BpfMap which is used for IPv4 bpf offload. */
public class TetherDownstream4Value extends Struct {
@Field(order = 0, type = Type.U32)
public final long oif;
// The ethhdr struct which is defined in uapi/linux/if_ether.h
@Field(order = 1, type = Type.EUI48)
public final MacAddress ethDstMac;
@Field(order = 2, type = Type.EUI48)
public final MacAddress ethSrcMac;
@Field(order = 3, type = Type.UBE16)
public final int ethProto; // Packet type ID field.
@Field(order = 4, type = Type.U16)
public final int pmtu;
@Field(order = 5, type = Type.ByteArray, arraysize = 4)
public final byte[] src4;
@Field(order = 6, type = Type.ByteArray, arraysize = 4)
public final byte[] dst4;
@Field(order = 7, type = Type.UBE16)
public final int srcPort;
@Field(order = 8, type = Type.UBE16)
public final int dstPort;
// TODO: consider using U64.
@Field(order = 9, type = Type.U63)
public final long lastUsed;
public TetherDownstream4Value(final long oif, @NonNull final MacAddress ethDstMac,
@NonNull final MacAddress ethSrcMac, final int ethProto, final int pmtu,
final byte[] src4, final byte[] dst4, final int srcPort,
final int dstPort, final long lastUsed) {
Objects.requireNonNull(ethDstMac);
Objects.requireNonNull(ethSrcMac);
this.oif = oif;
this.ethDstMac = ethDstMac;
this.ethSrcMac = ethSrcMac;
this.ethProto = ethProto;
this.pmtu = pmtu;
this.src4 = src4;
this.dst4 = dst4;
this.srcPort = srcPort;
this.dstPort = dstPort;
this.lastUsed = lastUsed;
}
@Override
public String toString() {
try {
return String.format(
"oif: %d, ethDstMac: %s, ethSrcMac: %s, ethProto: %d, pmtu: %d, "
+ "src4: %s, dst4: %s, srcPort: %d, dstPort: %d, "
+ "lastUsed: %d",
oif, ethDstMac, ethSrcMac, ethProto, pmtu,
InetAddress.getByAddress(src4), InetAddress.getByAddress(dst4),
Short.toUnsignedInt((short) srcPort), Short.toUnsignedInt((short) dstPort),
lastUsed);
} catch (UnknownHostException | IllegalArgumentException e) {
return String.format("Invalid IP address", e);
}
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.networkstack.tethering;
import android.net.MacAddress;
import androidx.annotation.NonNull;
import com.android.net.module.util.Struct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.Objects;
/** The key of BpfMap which is used for IPv4 bpf offload. */
public class TetherUpstream4Key extends Struct {
@Field(order = 0, type = Type.U32)
public final long iif;
@Field(order = 1, type = Type.EUI48)
public final MacAddress dstMac;
@Field(order = 2, type = Type.U8, padding = 1)
public final short l4proto;
@Field(order = 3, type = Type.ByteArray, arraysize = 4)
public final byte[] src4;
@Field(order = 4, type = Type.ByteArray, arraysize = 4)
public final byte[] dst4;
@Field(order = 5, type = Type.UBE16)
public final int srcPort;
@Field(order = 6, type = Type.UBE16)
public final int dstPort;
public TetherUpstream4Key(final long iif, @NonNull final MacAddress dstMac, final short l4proto,
final byte[] src4, final byte[] dst4, final int srcPort,
final int dstPort) {
Objects.requireNonNull(dstMac);
this.iif = iif;
this.dstMac = dstMac;
this.l4proto = l4proto;
this.src4 = src4;
this.dst4 = dst4;
this.srcPort = srcPort;
this.dstPort = dstPort;
}
@Override
public String toString() {
try {
return String.format(
"iif: %d, dstMac: %s, l4proto: %d, src4: %s, dst4: %s, "
+ "srcPort: %d, dstPort: %d",
iif, dstMac, l4proto,
Inet4Address.getByAddress(src4), Inet4Address.getByAddress(dst4),
Short.toUnsignedInt((short) srcPort), Short.toUnsignedInt((short) dstPort));
} catch (UnknownHostException | IllegalArgumentException e) {
return String.format("Invalid IP address", e);
}
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.networkstack.tethering;
import android.net.MacAddress;
import androidx.annotation.NonNull;
import com.android.net.module.util.Struct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Objects;
/** The value of BpfMap which is used for IPv4 bpf offload. */
public class TetherUpstream4Value extends Struct {
@Field(order = 0, type = Type.U32)
public final long oif;
// The ethhdr struct which is defined in uapi/linux/if_ether.h
@Field(order = 1, type = Type.EUI48)
public final MacAddress ethDstMac;
@Field(order = 2, type = Type.EUI48)
public final MacAddress ethSrcMac;
@Field(order = 3, type = Type.UBE16)
public final int ethProto; // Packet type ID field.
@Field(order = 4, type = Type.U16)
public final int pmtu;
@Field(order = 5, type = Type.ByteArray, arraysize = 16)
public final byte[] src46;
@Field(order = 6, type = Type.ByteArray, arraysize = 16)
public final byte[] dst46;
@Field(order = 7, type = Type.UBE16)
public final int srcPort;
@Field(order = 8, type = Type.UBE16)
public final int dstPort;
// TODO: consider using U64.
@Field(order = 9, type = Type.U63)
public final long lastUsed;
public TetherUpstream4Value(final long oif, @NonNull final MacAddress ethDstMac,
@NonNull final MacAddress ethSrcMac, final int ethProto, final int pmtu,
final byte[] src46, final byte[] dst46, final int srcPort,
final int dstPort, final long lastUsed) {
Objects.requireNonNull(ethDstMac);
Objects.requireNonNull(ethSrcMac);
this.oif = oif;
this.ethDstMac = ethDstMac;
this.ethSrcMac = ethSrcMac;
this.ethProto = ethProto;
this.pmtu = pmtu;
this.src46 = src46;
this.dst46 = dst46;
this.srcPort = srcPort;
this.dstPort = dstPort;
this.lastUsed = lastUsed;
}
@Override
public String toString() {
try {
return String.format(
"oif: %d, ethDstMac: %s, ethSrcMac: %s, ethProto: %d, pmtu: %d, "
+ "src46: %s, dst46: %s, srcPort: %d, dstPort: %d, "
+ "lastUsed: %d",
oif, ethDstMac, ethSrcMac, ethProto, pmtu,
InetAddress.getByAddress(src46), InetAddress.getByAddress(dst46),
Short.toUnsignedInt((short) srcPort), Short.toUnsignedInt((short) dstPort),
lastUsed);
} catch (UnknownHostException | IllegalArgumentException e) {
return String.format("Invalid IP address", e);
}
}
}

View File

@@ -104,12 +104,16 @@ import com.android.networkstack.tethering.BpfCoordinator;
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
import com.android.networkstack.tethering.BpfMap;
import com.android.networkstack.tethering.PrivateAddressCoordinator;
import com.android.networkstack.tethering.TetherDownstream4Key;
import com.android.networkstack.tethering.TetherDownstream4Value;
import com.android.networkstack.tethering.TetherDownstream6Key;
import com.android.networkstack.tethering.TetherDownstream6Value;
import com.android.networkstack.tethering.TetherLimitKey;
import com.android.networkstack.tethering.TetherLimitValue;
import com.android.networkstack.tethering.TetherStatsKey;
import com.android.networkstack.tethering.TetherStatsValue;
import com.android.networkstack.tethering.TetherUpstream4Key;
import com.android.networkstack.tethering.TetherUpstream4Value;
import com.android.networkstack.tethering.TetheringConfiguration;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
@@ -173,6 +177,8 @@ public class IpServerTest {
@Mock private NetworkStatsManager mStatsManager;
@Mock private TetheringConfiguration mTetherConfig;
@Mock private ConntrackMonitor mConntrackMonitor;
@Mock private BpfMap<TetherDownstream4Key, TetherDownstream4Value> mBpfDownstream4Map;
@Mock private BpfMap<TetherUpstream4Key, TetherUpstream4Value> mBpfUpstream4Map;
@Mock private BpfMap<TetherDownstream6Key, TetherDownstream6Value> mBpfDownstream6Map;
@Mock private BpfMap<TetherStatsKey, TetherStatsValue> mBpfStatsMap;
@Mock private BpfMap<TetherLimitKey, TetherLimitValue> mBpfLimitMap;
@@ -302,6 +308,18 @@ public class IpServerTest {
return mConntrackMonitor;
}
@Nullable
public BpfMap<TetherDownstream4Key, TetherDownstream4Value>
getBpfDownstream4Map() {
return mBpfDownstream4Map;
}
@Nullable
public BpfMap<TetherUpstream4Key, TetherUpstream4Value>
getBpfUpstream4Map() {
return mBpfUpstream4Map;
}
@Nullable
public BpfMap<TetherDownstream6Key, TetherDownstream6Value>
getBpfDownstream6Map() {

View File

@@ -158,6 +158,8 @@ public class BpfCoordinatorTest {
@Mock private IpServer mIpServer2;
@Mock private TetheringConfiguration mTetherConfig;
@Mock private ConntrackMonitor mConntrackMonitor;
@Mock private BpfMap<TetherDownstream4Key, TetherDownstream4Value> mBpfDownstream4Map;
@Mock private BpfMap<TetherUpstream4Key, TetherUpstream4Value> mBpfUpstream4Map;
@Mock private BpfMap<TetherDownstream6Key, TetherDownstream6Value> mBpfDownstream6Map;
// Late init since methods must be called by the thread that created this object.
@@ -202,6 +204,18 @@ public class BpfCoordinatorTest {
return mConntrackMonitor;
}
@Nullable
public BpfMap<TetherDownstream4Key, TetherDownstream4Value>
getBpfDownstream4Map() {
return mBpfDownstream4Map;
}
@Nullable
public BpfMap<TetherUpstream4Key, TetherUpstream4Value>
getBpfUpstream4Map() {
return mBpfUpstream4Map;
}
@Nullable
public BpfMap<TetherDownstream6Key, TetherDownstream6Value>
getBpfDownstream6Map() {