Merge changes I5af6ce96,Ibc1f6813
* changes:
Refactor make{Tether4Key, Tether4Value ConntrackEvent} helper
BpfCoordinatorTest: refactor upstream and downstream setup functions
This commit is contained in:
@@ -1487,7 +1487,8 @@ public class BpfCoordinator {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private byte[] toIpv4MappedAddressBytes(Inet4Address ia4) {
|
||||
@VisibleForTesting
|
||||
static byte[] toIpv4MappedAddressBytes(Inet4Address ia4) {
|
||||
final byte[] addr4 = ia4.getAddress();
|
||||
final byte[] addr6 = new byte[16];
|
||||
addr6[10] = (byte) 0xff;
|
||||
|
||||
@@ -47,6 +47,7 @@ import static com.android.networkstack.tethering.BpfCoordinator.NON_OFFLOADED_UP
|
||||
import static com.android.networkstack.tethering.BpfCoordinator.StatsType;
|
||||
import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_IFACE;
|
||||
import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_UID;
|
||||
import static com.android.networkstack.tethering.BpfCoordinator.toIpv4MappedAddressBytes;
|
||||
import static com.android.networkstack.tethering.BpfUtils.DOWNSTREAM;
|
||||
import static com.android.networkstack.tethering.BpfUtils.UPSTREAM;
|
||||
import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
|
||||
@@ -129,6 +130,7 @@ import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@@ -138,22 +140,225 @@ public class BpfCoordinatorTest {
|
||||
public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
|
||||
|
||||
private static final int TEST_NET_ID = 24;
|
||||
private static final int TEST_NET_ID2 = 25;
|
||||
|
||||
private static final int INVALID_IFINDEX = 0;
|
||||
private static final int UPSTREAM_IFINDEX = 1001;
|
||||
private static final int DOWNSTREAM_IFINDEX = 1002;
|
||||
private static final int UPSTREAM_IFINDEX2 = 1002;
|
||||
private static final int DOWNSTREAM_IFINDEX = 1003;
|
||||
private static final int DOWNSTREAM_IFINDEX2 = 1004;
|
||||
|
||||
private static final String UPSTREAM_IFACE = "rmnet0";
|
||||
private static final String UPSTREAM_IFACE2 = "wlan0";
|
||||
|
||||
private static final MacAddress DOWNSTREAM_MAC = MacAddress.fromString("12:34:56:78:90:ab");
|
||||
private static final MacAddress DOWNSTREAM_MAC2 = MacAddress.fromString("ab:90:78:56:34:12");
|
||||
|
||||
private static final MacAddress MAC_A = MacAddress.fromString("00:00:00:00:00:0a");
|
||||
private static final MacAddress MAC_B = MacAddress.fromString("11:22:33:00:00:0b");
|
||||
|
||||
private static final InetAddress NEIGH_A = InetAddresses.parseNumericAddress("2001:db8::1");
|
||||
private static final InetAddress NEIGH_B = InetAddresses.parseNumericAddress("2001:db8::2");
|
||||
|
||||
private static final Inet4Address REMOTE_ADDR =
|
||||
(Inet4Address) InetAddresses.parseNumericAddress("140.112.8.116");
|
||||
private static final Inet4Address PUBLIC_ADDR =
|
||||
(Inet4Address) InetAddresses.parseNumericAddress("1.0.0.1");
|
||||
private static final Inet4Address PUBLIC_ADDR2 =
|
||||
(Inet4Address) InetAddresses.parseNumericAddress("1.0.0.2");
|
||||
private static final Inet4Address PRIVATE_ADDR =
|
||||
(Inet4Address) InetAddresses.parseNumericAddress("192.168.80.12");
|
||||
private static final Inet4Address PRIVATE_ADDR2 =
|
||||
(Inet4Address) InetAddresses.parseNumericAddress("192.168.90.12");
|
||||
|
||||
// Generally, public port and private port are the same in the NAT conntrack message.
|
||||
// TODO: consider using different private port and public port for testing.
|
||||
private static final short REMOTE_PORT = (short) 443;
|
||||
private static final short PUBLIC_PORT = (short) 62449;
|
||||
private static final short PUBLIC_PORT2 = (short) 62450;
|
||||
private static final short PRIVATE_PORT = (short) 62449;
|
||||
private static final short PRIVATE_PORT2 = (short) 62450;
|
||||
|
||||
private static final InterfaceParams UPSTREAM_IFACE_PARAMS = new InterfaceParams(
|
||||
UPSTREAM_IFACE, UPSTREAM_IFINDEX, null /* macAddr, rawip */,
|
||||
NetworkStackConstants.ETHER_MTU);
|
||||
private static final InterfaceParams UPSTREAM_IFACE_PARAMS2 = new InterfaceParams(
|
||||
UPSTREAM_IFACE2, UPSTREAM_IFINDEX2, MacAddress.fromString("44:55:66:00:00:0c"),
|
||||
NetworkStackConstants.ETHER_MTU);
|
||||
|
||||
private static final HashMap<Integer, UpstreamInformation> UPSTREAM_INFORMATIONS =
|
||||
new HashMap<Integer, UpstreamInformation>() {{
|
||||
put(UPSTREAM_IFINDEX, new UpstreamInformation(UPSTREAM_IFACE_PARAMS,
|
||||
PUBLIC_ADDR, NetworkCapabilities.TRANSPORT_CELLULAR, TEST_NET_ID));
|
||||
put(UPSTREAM_IFINDEX2, new UpstreamInformation(UPSTREAM_IFACE_PARAMS2,
|
||||
PUBLIC_ADDR2, NetworkCapabilities.TRANSPORT_WIFI, TEST_NET_ID2));
|
||||
}};
|
||||
|
||||
private static final ClientInfo CLIENT_INFO_A = new ClientInfo(DOWNSTREAM_IFINDEX,
|
||||
DOWNSTREAM_MAC, PRIVATE_ADDR, MAC_A);
|
||||
private static final ClientInfo CLIENT_INFO_B = new ClientInfo(DOWNSTREAM_IFINDEX2,
|
||||
DOWNSTREAM_MAC2, PRIVATE_ADDR2, MAC_B);
|
||||
|
||||
private static class UpstreamInformation {
|
||||
public final InterfaceParams interfaceParams;
|
||||
public final Inet4Address address;
|
||||
public final int transportType;
|
||||
public final int netId;
|
||||
|
||||
UpstreamInformation(final InterfaceParams interfaceParams,
|
||||
final Inet4Address address, int transportType, int netId) {
|
||||
this.interfaceParams = interfaceParams;
|
||||
this.address = address;
|
||||
this.transportType = transportType;
|
||||
this.netId = netId;
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestUpstream4Key {
|
||||
public static class Builder {
|
||||
private long mIif = DOWNSTREAM_IFINDEX;
|
||||
private MacAddress mDstMac = DOWNSTREAM_MAC;
|
||||
private short mL4proto = (short) IPPROTO_TCP;
|
||||
private byte[] mSrc4 = PRIVATE_ADDR.getAddress();
|
||||
private byte[] mDst4 = REMOTE_ADDR.getAddress();
|
||||
private int mSrcPort = PRIVATE_PORT;
|
||||
private int mDstPort = REMOTE_PORT;
|
||||
|
||||
Builder() {}
|
||||
|
||||
public Builder setProto(int proto) {
|
||||
if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
|
||||
fail("Not support protocol " + proto);
|
||||
}
|
||||
mL4proto = (short) proto;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Tether4Key build() {
|
||||
return new Tether4Key(mIif, mDstMac, mL4proto, mSrc4, mDst4, mSrcPort, mDstPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestDownstream4Key {
|
||||
public static class Builder {
|
||||
private long mIif = UPSTREAM_IFINDEX;
|
||||
private MacAddress mDstMac = MacAddress.ALL_ZEROS_ADDRESS /* dstMac (rawip) */;
|
||||
private short mL4proto = (short) IPPROTO_TCP;
|
||||
private byte[] mSrc4 = REMOTE_ADDR.getAddress();
|
||||
private byte[] mDst4 = PUBLIC_ADDR.getAddress();
|
||||
private int mSrcPort = REMOTE_PORT;
|
||||
private int mDstPort = PUBLIC_PORT;
|
||||
|
||||
Builder() {}
|
||||
|
||||
public Builder setProto(int proto) {
|
||||
if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
|
||||
fail("Not support protocol " + proto);
|
||||
}
|
||||
mL4proto = (short) proto;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Tether4Key build() {
|
||||
return new Tether4Key(mIif, mDstMac, mL4proto, mSrc4, mDst4, mSrcPort, mDstPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestUpstream4Value {
|
||||
public static class Builder {
|
||||
private long mOif = UPSTREAM_IFINDEX;
|
||||
private MacAddress mEthDstMac = MacAddress.ALL_ZEROS_ADDRESS /* dstMac (rawip) */;
|
||||
private MacAddress mEthSrcMac = MacAddress.ALL_ZEROS_ADDRESS /* dstMac (rawip) */;
|
||||
private int mEthProto = ETH_P_IP;
|
||||
private short mPmtu = NetworkStackConstants.ETHER_MTU;
|
||||
private byte[] mSrc46 = toIpv4MappedAddressBytes(PUBLIC_ADDR);
|
||||
private byte[] mDst46 = toIpv4MappedAddressBytes(REMOTE_ADDR);
|
||||
private int mSrcPort = PUBLIC_PORT;
|
||||
private int mDstPort = REMOTE_PORT;
|
||||
private long mLastUsed = 0;
|
||||
|
||||
Builder() {}
|
||||
|
||||
public Tether4Value build() {
|
||||
return new Tether4Value(mOif, mEthDstMac, mEthSrcMac, mEthProto, mPmtu,
|
||||
mSrc46, mDst46, mSrcPort, mDstPort, mLastUsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestDownstream4Value {
|
||||
public static class Builder {
|
||||
private long mOif = DOWNSTREAM_IFINDEX;
|
||||
private MacAddress mEthDstMac = MAC_A /* client mac */;
|
||||
private MacAddress mEthSrcMac = DOWNSTREAM_MAC;
|
||||
private int mEthProto = ETH_P_IP;
|
||||
private short mPmtu = NetworkStackConstants.ETHER_MTU;
|
||||
private byte[] mSrc46 = toIpv4MappedAddressBytes(REMOTE_ADDR);
|
||||
private byte[] mDst46 = toIpv4MappedAddressBytes(PRIVATE_ADDR);
|
||||
private int mSrcPort = REMOTE_PORT;
|
||||
private int mDstPort = PRIVATE_PORT;
|
||||
private long mLastUsed = 0;
|
||||
|
||||
Builder() {}
|
||||
|
||||
public Tether4Value build() {
|
||||
return new Tether4Value(mOif, mEthDstMac, mEthSrcMac, mEthProto, mPmtu,
|
||||
mSrc46, mDst46, mSrcPort, mDstPort, mLastUsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestConntrackEvent {
|
||||
public static class Builder {
|
||||
private short mMsgType = IPCTNL_MSG_CT_NEW;
|
||||
private short mProto = (short) IPPROTO_TCP;
|
||||
private Inet4Address mPrivateAddr = PRIVATE_ADDR;
|
||||
private Inet4Address mPublicAddr = PUBLIC_ADDR;
|
||||
private Inet4Address mRemoteAddr = REMOTE_ADDR;
|
||||
private short mPrivatePort = PRIVATE_PORT;
|
||||
private short mPublicPort = PUBLIC_PORT;
|
||||
private short mRemotePort = REMOTE_PORT;
|
||||
|
||||
Builder() {}
|
||||
|
||||
public Builder setMsgType(short msgType) {
|
||||
if (msgType != IPCTNL_MSG_CT_NEW && msgType != IPCTNL_MSG_CT_DELETE) {
|
||||
fail("Not support message type " + msgType);
|
||||
}
|
||||
mMsgType = (short) msgType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setProto(int proto) {
|
||||
if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
|
||||
fail("Not support protocol " + proto);
|
||||
}
|
||||
mProto = (short) proto;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRemotePort(int remotePort) {
|
||||
mRemotePort = (short) remotePort;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConntrackEvent build() {
|
||||
final int status = (mMsgType == IPCTNL_MSG_CT_NEW) ? ESTABLISHED_MASK : DYING_MASK;
|
||||
final int timeoutSec = (mMsgType == IPCTNL_MSG_CT_NEW) ? 100 /* nonzero, new */
|
||||
: 0 /* unused, delete */;
|
||||
return new ConntrackEvent(
|
||||
(short) (NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8 | mMsgType),
|
||||
new Tuple(new TupleIpv4(mPrivateAddr, mRemoteAddr),
|
||||
new TupleProto((byte) mProto, mPrivatePort, mRemotePort)),
|
||||
new Tuple(new TupleIpv4(mRemoteAddr, mPublicAddr),
|
||||
new TupleProto((byte) mProto, mRemotePort, mPublicPort)),
|
||||
status,
|
||||
timeoutSec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Mock private NetworkStatsManager mStatsManager;
|
||||
@Mock private INetd mNetd;
|
||||
@@ -161,8 +366,6 @@ public class BpfCoordinatorTest {
|
||||
@Mock private IpServer mIpServer2;
|
||||
@Mock private TetheringConfiguration mTetherConfig;
|
||||
@Mock private ConntrackMonitor mConntrackMonitor;
|
||||
@Mock private BpfMap<Tether4Key, Tether4Value> mBpfDownstream4Map;
|
||||
@Mock private BpfMap<Tether4Key, Tether4Value> mBpfUpstream4Map;
|
||||
@Mock private BpfMap<TetherDownstream6Key, Tether6Value> mBpfDownstream6Map;
|
||||
@Mock private BpfMap<TetherUpstream6Key, Tether6Value> mBpfUpstream6Map;
|
||||
@Mock private BpfMap<TetherDevKey, TetherDevValue> mBpfDevMap;
|
||||
@@ -179,6 +382,10 @@ public class BpfCoordinatorTest {
|
||||
private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
|
||||
ArgumentCaptor.forClass(ArrayList.class);
|
||||
private final TestLooper mTestLooper = new TestLooper();
|
||||
private final BpfMap<Tether4Key, Tether4Value> mBpfDownstream4Map =
|
||||
spy(new TestBpfMap<>(Tether4Key.class, Tether4Value.class));
|
||||
private final BpfMap<Tether4Key, Tether4Value> mBpfUpstream4Map =
|
||||
spy(new TestBpfMap<>(Tether4Key.class, Tether4Value.class));
|
||||
private final TestBpfMap<TetherStatsKey, TetherStatsValue> mBpfStatsMap =
|
||||
spy(new TestBpfMap<>(TetherStatsKey.class, TetherStatsValue.class));
|
||||
private final TestBpfMap<TetherLimitKey, TetherLimitValue> mBpfLimitMap =
|
||||
@@ -1244,140 +1451,67 @@ public class BpfCoordinatorTest {
|
||||
// | Sever +---------+ Upstream | Downstream +---------+ Client |
|
||||
// +------------+ +------------+------------+ +------------+
|
||||
// remote ip public ip private ip
|
||||
// 140.112.8.116:443 100.81.179.1:62449 192.168.80.12:62449
|
||||
// 140.112.8.116:443 1.0.0.1:62449 192.168.80.12:62449
|
||||
//
|
||||
private static final Inet4Address REMOTE_ADDR =
|
||||
(Inet4Address) InetAddresses.parseNumericAddress("140.112.8.116");
|
||||
private static final Inet4Address PUBLIC_ADDR =
|
||||
(Inet4Address) InetAddresses.parseNumericAddress("100.81.179.1");
|
||||
private static final Inet4Address PRIVATE_ADDR =
|
||||
(Inet4Address) InetAddresses.parseNumericAddress("192.168.80.12");
|
||||
|
||||
// IPv4-mapped IPv6 addresses
|
||||
// Remote addrress ::ffff:140.112.8.116
|
||||
// Public addrress ::ffff:100.81.179.1
|
||||
// Private addrress ::ffff:192.168.80.12
|
||||
private static final byte[] REMOTE_ADDR_V4MAPPED_BYTES = new byte[] {
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0x8c, (byte) 0x70, (byte) 0x08, (byte) 0x74 };
|
||||
private static final byte[] PUBLIC_ADDR_V4MAPPED_BYTES = new byte[] {
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0x64, (byte) 0x51, (byte) 0xb3, (byte) 0x01 };
|
||||
private static final byte[] PRIVATE_ADDR_V4MAPPED_BYTES = new byte[] {
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xc0, (byte) 0xa8, (byte) 0x50, (byte) 0x0c };
|
||||
|
||||
// Generally, public port and private port are the same in the NAT conntrack message.
|
||||
// TODO: consider using different private port and public port for testing.
|
||||
private static final short REMOTE_PORT = (short) 443;
|
||||
private static final short PUBLIC_PORT = (short) 62449;
|
||||
private static final short PRIVATE_PORT = (short) 62449;
|
||||
|
||||
@NonNull
|
||||
private Tether4Key makeUpstream4Key(int proto) {
|
||||
if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
|
||||
fail("Not support protocol " + proto);
|
||||
}
|
||||
return new Tether4Key(DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC, (short) proto,
|
||||
PRIVATE_ADDR.getAddress(), REMOTE_ADDR.getAddress(), PRIVATE_PORT, REMOTE_PORT);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Tether4Key makeDownstream4Key(int proto) {
|
||||
if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
|
||||
fail("Not support protocol " + proto);
|
||||
}
|
||||
return new Tether4Key(UPSTREAM_IFINDEX,
|
||||
MacAddress.ALL_ZEROS_ADDRESS /* dstMac (rawip) */, (short) proto,
|
||||
REMOTE_ADDR.getAddress(), PUBLIC_ADDR.getAddress(), REMOTE_PORT, PUBLIC_PORT);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Tether4Value makeUpstream4Value() {
|
||||
return new Tether4Value(UPSTREAM_IFINDEX,
|
||||
MacAddress.ALL_ZEROS_ADDRESS /* ethDstMac (rawip) */,
|
||||
MacAddress.ALL_ZEROS_ADDRESS /* ethSrcMac (rawip) */, ETH_P_IP,
|
||||
NetworkStackConstants.ETHER_MTU, PUBLIC_ADDR_V4MAPPED_BYTES,
|
||||
REMOTE_ADDR_V4MAPPED_BYTES, PUBLIC_PORT, REMOTE_PORT, 0 /* lastUsed */);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Tether4Value makeDownstream4Value() {
|
||||
return new Tether4Value(DOWNSTREAM_IFINDEX, MAC_A /* client mac */, DOWNSTREAM_MAC,
|
||||
ETH_P_IP, NetworkStackConstants.ETHER_MTU, REMOTE_ADDR_V4MAPPED_BYTES,
|
||||
PRIVATE_ADDR_V4MAPPED_BYTES, REMOTE_PORT, PRIVATE_PORT, 0 /* lastUsed */);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Tether4Key makeDownstream4Key() {
|
||||
return makeDownstream4Key(IPPROTO_TCP);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private ConntrackEvent makeTestConntrackEvent(short msgType, int proto, short remotePort) {
|
||||
if (msgType != IPCTNL_MSG_CT_NEW && msgType != IPCTNL_MSG_CT_DELETE) {
|
||||
fail("Not support message type " + msgType);
|
||||
}
|
||||
if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
|
||||
fail("Not support protocol " + proto);
|
||||
// Setup upstream interface to BpfCoordinator.
|
||||
//
|
||||
// @param coordinator BpfCoordinator instance.
|
||||
// @param upstreamIfindex upstream interface index. can be the following values.
|
||||
// INVALID_IFINDEX: no upstream interface
|
||||
// UPSTREAM_IFINDEX: CELLULAR (raw ip interface)
|
||||
// UPSTREAM_IFINDEX2: WIFI (ethernet interface)
|
||||
private void setUpstreamInformationTo(final BpfCoordinator coordinator,
|
||||
@Nullable Integer upstreamIfindex) {
|
||||
if (upstreamIfindex == INVALID_IFINDEX) {
|
||||
coordinator.updateUpstreamNetworkState(null);
|
||||
return;
|
||||
}
|
||||
|
||||
final int status = (msgType == IPCTNL_MSG_CT_NEW) ? ESTABLISHED_MASK : DYING_MASK;
|
||||
final int timeoutSec = (msgType == IPCTNL_MSG_CT_NEW) ? 100 /* nonzero, new */
|
||||
: 0 /* unused, delete */;
|
||||
return new ConntrackEvent(
|
||||
(short) (NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8 | msgType),
|
||||
new Tuple(new TupleIpv4(PRIVATE_ADDR, REMOTE_ADDR),
|
||||
new TupleProto((byte) proto, PRIVATE_PORT, remotePort)),
|
||||
new Tuple(new TupleIpv4(REMOTE_ADDR, PUBLIC_ADDR),
|
||||
new TupleProto((byte) proto, remotePort, PUBLIC_PORT)),
|
||||
status,
|
||||
timeoutSec);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private ConntrackEvent makeTestConntrackEvent(short msgType, int proto) {
|
||||
return makeTestConntrackEvent(msgType, proto, REMOTE_PORT);
|
||||
}
|
||||
|
||||
private void setUpstreamInformationTo(final BpfCoordinator coordinator) {
|
||||
final LinkProperties lp = new LinkProperties();
|
||||
lp.setInterfaceName(UPSTREAM_IFACE);
|
||||
lp.addLinkAddress(new LinkAddress(PUBLIC_ADDR, 32 /* prefix length */));
|
||||
final NetworkCapabilities capabilities = new NetworkCapabilities()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
|
||||
coordinator.updateUpstreamNetworkState(new UpstreamNetworkState(lp, capabilities,
|
||||
new Network(TEST_NET_ID)));
|
||||
}
|
||||
|
||||
private void setDownstreamAndClientInformationTo(final BpfCoordinator coordinator) {
|
||||
final ClientInfo clientInfo = new ClientInfo(DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC,
|
||||
PRIVATE_ADDR, MAC_A /* client mac */);
|
||||
coordinator.tetherOffloadClientAdd(mIpServer, clientInfo);
|
||||
}
|
||||
|
||||
private void initBpfCoordinatorForRule4(final BpfCoordinator coordinator) throws Exception {
|
||||
// Needed because addUpstreamIfindexToMap only updates upstream information when polling
|
||||
// was started.
|
||||
coordinator.startPolling();
|
||||
|
||||
// Needed because two reasons: (1) BpfConntrackEventConsumer#accept only performs cleanup
|
||||
// when both upstream and downstream rules are removed. (2) tetherOffloadRuleRemove of
|
||||
// api31.BpfCoordinatorShimImpl only decreases the count while the entry is deleted.
|
||||
// In the other words, deleteEntry returns true.
|
||||
doReturn(true).when(mBpfUpstream4Map).deleteEntry(any());
|
||||
doReturn(true).when(mBpfDownstream4Map).deleteEntry(any());
|
||||
final UpstreamInformation upstreamInfo = UPSTREAM_INFORMATIONS.get(upstreamIfindex);
|
||||
if (upstreamInfo == null) {
|
||||
fail("Not support upstream interface index " + upstreamIfindex);
|
||||
}
|
||||
|
||||
// Needed because BpfCoordinator#addUpstreamIfindexToMap queries interface parameter for
|
||||
// interface index.
|
||||
doReturn(UPSTREAM_IFACE_PARAMS).when(mDeps).getInterfaceParams(UPSTREAM_IFACE);
|
||||
doReturn(upstreamInfo.interfaceParams).when(mDeps).getInterfaceParams(
|
||||
upstreamInfo.interfaceParams.name);
|
||||
coordinator.addUpstreamNameToLookupTable(upstreamInfo.interfaceParams.index,
|
||||
upstreamInfo.interfaceParams.name);
|
||||
|
||||
coordinator.addUpstreamNameToLookupTable(UPSTREAM_IFINDEX, UPSTREAM_IFACE);
|
||||
setUpstreamInformationTo(coordinator);
|
||||
setDownstreamAndClientInformationTo(coordinator);
|
||||
final LinkProperties lp = new LinkProperties();
|
||||
lp.setInterfaceName(upstreamInfo.interfaceParams.name);
|
||||
lp.addLinkAddress(new LinkAddress(upstreamInfo.address, 32 /* prefix length */));
|
||||
final NetworkCapabilities capabilities = new NetworkCapabilities()
|
||||
.addTransportType(upstreamInfo.transportType);
|
||||
coordinator.updateUpstreamNetworkState(new UpstreamNetworkState(lp, capabilities,
|
||||
new Network(upstreamInfo.netId)));
|
||||
}
|
||||
|
||||
// Setup downstream interface and its client information to BpfCoordinator.
|
||||
//
|
||||
// @param coordinator BpfCoordinator instance.
|
||||
// @param downstreamIfindex downstream interface index. can be the following values.
|
||||
// DOWNSTREAM_IFINDEX: a client information which uses MAC_A is added.
|
||||
// DOWNSTREAM_IFINDEX2: a client information which uses MAC_B is added.
|
||||
// TODO: refactor this function once the client switches between each downstream interface.
|
||||
private void addDownstreamAndClientInformationTo(final BpfCoordinator coordinator,
|
||||
int downstreamIfindex) {
|
||||
if (downstreamIfindex != DOWNSTREAM_IFINDEX && downstreamIfindex != DOWNSTREAM_IFINDEX2) {
|
||||
fail("Not support downstream interface index " + downstreamIfindex);
|
||||
}
|
||||
|
||||
if (downstreamIfindex == DOWNSTREAM_IFINDEX) {
|
||||
coordinator.tetherOffloadClientAdd(mIpServer, CLIENT_INFO_A);
|
||||
} else {
|
||||
coordinator.tetherOffloadClientAdd(mIpServer2, CLIENT_INFO_B);
|
||||
}
|
||||
}
|
||||
|
||||
private void initBpfCoordinatorForRule4(final BpfCoordinator coordinator) throws Exception {
|
||||
setUpstreamInformationTo(coordinator, UPSTREAM_IFINDEX);
|
||||
addDownstreamAndClientInformationTo(coordinator, DOWNSTREAM_IFINDEX);
|
||||
}
|
||||
|
||||
// TODO: Test the IPv4 and IPv6 exist concurrently.
|
||||
@@ -1401,18 +1535,25 @@ public class BpfCoordinatorTest {
|
||||
// because the protocol is not an element of the value. Consider using different address
|
||||
// or port to make them different for better testing.
|
||||
// TODO: Make the values of {TCP, UDP} rules different.
|
||||
final Tether4Key expectedUpstream4KeyTcp = makeUpstream4Key(IPPROTO_TCP);
|
||||
final Tether4Key expectedDownstream4KeyTcp = makeDownstream4Key(IPPROTO_TCP);
|
||||
final Tether4Value expectedUpstream4ValueTcp = makeUpstream4Value();
|
||||
final Tether4Value expectedDownstream4ValueTcp = makeDownstream4Value();
|
||||
final Tether4Key expectedUpstream4KeyTcp = new TestUpstream4Key.Builder()
|
||||
.setProto(IPPROTO_TCP).build();
|
||||
final Tether4Key expectedDownstream4KeyTcp = new TestDownstream4Key.Builder()
|
||||
.setProto(IPPROTO_TCP).build();
|
||||
final Tether4Value expectedUpstream4ValueTcp = new TestUpstream4Value.Builder().build();
|
||||
final Tether4Value expectedDownstream4ValueTcp = new TestDownstream4Value.Builder().build();
|
||||
|
||||
final Tether4Key expectedUpstream4KeyUdp = makeUpstream4Key(IPPROTO_UDP);
|
||||
final Tether4Key expectedDownstream4KeyUdp = makeDownstream4Key(IPPROTO_UDP);
|
||||
final Tether4Value expectedUpstream4ValueUdp = makeUpstream4Value();
|
||||
final Tether4Value expectedDownstream4ValueUdp = makeDownstream4Value();
|
||||
final Tether4Key expectedUpstream4KeyUdp = new TestUpstream4Key.Builder()
|
||||
.setProto(IPPROTO_UDP).build();
|
||||
final Tether4Key expectedDownstream4KeyUdp = new TestDownstream4Key.Builder()
|
||||
.setProto(IPPROTO_UDP).build();
|
||||
final Tether4Value expectedUpstream4ValueUdp = new TestUpstream4Value.Builder().build();
|
||||
final Tether4Value expectedDownstream4ValueUdp = new TestDownstream4Value.Builder().build();
|
||||
|
||||
// [1] Adding the first rule on current upstream immediately sends the quota.
|
||||
mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_NEW, IPPROTO_TCP));
|
||||
mConsumer.accept(new TestConntrackEvent.Builder()
|
||||
.setMsgType(IPCTNL_MSG_CT_NEW)
|
||||
.setProto(IPPROTO_TCP)
|
||||
.build());
|
||||
verifyTetherOffloadSetInterfaceQuota(inOrder, UPSTREAM_IFINDEX, limit, true /* isInit */);
|
||||
inOrder.verify(mBpfUpstream4Map)
|
||||
.insertEntry(eq(expectedUpstream4KeyTcp), eq(expectedUpstream4ValueTcp));
|
||||
@@ -1421,7 +1562,10 @@ public class BpfCoordinatorTest {
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
|
||||
// [2] Adding the second rule on current upstream does not send the quota.
|
||||
mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_NEW, IPPROTO_UDP));
|
||||
mConsumer.accept(new TestConntrackEvent.Builder()
|
||||
.setMsgType(IPCTNL_MSG_CT_NEW)
|
||||
.setProto(IPPROTO_UDP)
|
||||
.build());
|
||||
verifyNeverTetherOffloadSetInterfaceQuota(inOrder);
|
||||
inOrder.verify(mBpfUpstream4Map)
|
||||
.insertEntry(eq(expectedUpstream4KeyUdp), eq(expectedUpstream4ValueUdp));
|
||||
@@ -1430,7 +1574,10 @@ public class BpfCoordinatorTest {
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
|
||||
// [3] Removing the second rule on current upstream does not send the quota.
|
||||
mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_DELETE, IPPROTO_UDP));
|
||||
mConsumer.accept(new TestConntrackEvent.Builder()
|
||||
.setMsgType(IPCTNL_MSG_CT_DELETE)
|
||||
.setProto(IPPROTO_UDP)
|
||||
.build());
|
||||
verifyNeverTetherOffloadSetInterfaceQuota(inOrder);
|
||||
inOrder.verify(mBpfUpstream4Map).deleteEntry(eq(expectedUpstream4KeyUdp));
|
||||
inOrder.verify(mBpfDownstream4Map).deleteEntry(eq(expectedDownstream4KeyUdp));
|
||||
@@ -1439,7 +1586,10 @@ public class BpfCoordinatorTest {
|
||||
// [4] Removing the last rule on current upstream immediately sends the cleanup stuff.
|
||||
updateStatsEntryForTetherOffloadGetAndClearStats(
|
||||
buildTestTetherStatsParcel(UPSTREAM_IFINDEX, 0, 0, 0, 0));
|
||||
mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_DELETE, IPPROTO_TCP));
|
||||
mConsumer.accept(new TestConntrackEvent.Builder()
|
||||
.setMsgType(IPCTNL_MSG_CT_DELETE)
|
||||
.setProto(IPPROTO_TCP)
|
||||
.build());
|
||||
inOrder.verify(mBpfUpstream4Map).deleteEntry(eq(expectedUpstream4KeyTcp));
|
||||
inOrder.verify(mBpfDownstream4Map).deleteEntry(eq(expectedDownstream4KeyTcp));
|
||||
verifyTetherOffloadGetAndClearStats(inOrder, UPSTREAM_IFINDEX);
|
||||
@@ -1472,14 +1622,20 @@ public class BpfCoordinatorTest {
|
||||
final BpfCoordinator coordinator = makeBpfCoordinator();
|
||||
initBpfCoordinatorForRule4(coordinator);
|
||||
|
||||
mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_NEW, IPPROTO_TCP));
|
||||
mConsumer.accept(new TestConntrackEvent.Builder()
|
||||
.setMsgType(IPCTNL_MSG_CT_NEW)
|
||||
.setProto(IPPROTO_TCP)
|
||||
.build());
|
||||
verify(mBpfDevMap).updateEntry(eq(new TetherDevKey(UPSTREAM_IFINDEX)),
|
||||
eq(new TetherDevValue(UPSTREAM_IFINDEX)));
|
||||
verify(mBpfDevMap).updateEntry(eq(new TetherDevKey(DOWNSTREAM_IFINDEX)),
|
||||
eq(new TetherDevValue(DOWNSTREAM_IFINDEX)));
|
||||
clearInvocations(mBpfDevMap);
|
||||
|
||||
mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_NEW, IPPROTO_UDP));
|
||||
mConsumer.accept(new TestConntrackEvent.Builder()
|
||||
.setMsgType(IPCTNL_MSG_CT_NEW)
|
||||
.setProto(IPPROTO_UDP)
|
||||
.build());
|
||||
verify(mBpfDevMap, never()).updateEntry(any(), any());
|
||||
}
|
||||
|
||||
@@ -1559,10 +1715,10 @@ public class BpfCoordinatorTest {
|
||||
new TestBpfMap<>(Tether4Key.class, Tether4Value.class);
|
||||
doReturn(bpfUpstream4Map).when(mDeps).getBpfUpstream4Map();
|
||||
|
||||
final Tether4Key tcpKey = makeUpstream4Key(IPPROTO_TCP);
|
||||
final Tether4Key udpKey = makeUpstream4Key(IPPROTO_UDP);
|
||||
final Tether4Value tcpValue = makeUpstream4Value();
|
||||
final Tether4Value udpValue = makeUpstream4Value();
|
||||
final Tether4Key tcpKey = new TestUpstream4Key.Builder().setProto(IPPROTO_TCP).build();
|
||||
final Tether4Key udpKey = new TestUpstream4Key.Builder().setProto(IPPROTO_UDP).build();
|
||||
final Tether4Value tcpValue = new TestUpstream4Value.Builder().build();
|
||||
final Tether4Value udpValue = new TestUpstream4Value.Builder().build();
|
||||
|
||||
checkRefreshConntrackTimeout(bpfUpstream4Map, tcpKey, tcpValue, udpKey, udpValue);
|
||||
}
|
||||
@@ -1575,10 +1731,10 @@ public class BpfCoordinatorTest {
|
||||
new TestBpfMap<>(Tether4Key.class, Tether4Value.class);
|
||||
doReturn(bpfDownstream4Map).when(mDeps).getBpfDownstream4Map();
|
||||
|
||||
final Tether4Key tcpKey = makeDownstream4Key(IPPROTO_TCP);
|
||||
final Tether4Key udpKey = makeDownstream4Key(IPPROTO_UDP);
|
||||
final Tether4Value tcpValue = makeDownstream4Value();
|
||||
final Tether4Value udpValue = makeDownstream4Value();
|
||||
final Tether4Key tcpKey = new TestDownstream4Key.Builder().setProto(IPPROTO_TCP).build();
|
||||
final Tether4Key udpKey = new TestDownstream4Key.Builder().setProto(IPPROTO_UDP).build();
|
||||
final Tether4Value tcpValue = new TestDownstream4Value.Builder().build();
|
||||
final Tether4Value udpValue = new TestDownstream4Value.Builder().build();
|
||||
|
||||
checkRefreshConntrackTimeout(bpfDownstream4Map, tcpKey, tcpValue, udpKey, udpValue);
|
||||
}
|
||||
@@ -1592,26 +1748,46 @@ public class BpfCoordinatorTest {
|
||||
final short offloadedPort = 42;
|
||||
assertFalse(CollectionUtils.contains(NON_OFFLOADED_UPSTREAM_IPV4_TCP_PORTS,
|
||||
offloadedPort));
|
||||
mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_NEW, IPPROTO_TCP, offloadedPort));
|
||||
mConsumer.accept(new TestConntrackEvent.Builder()
|
||||
.setMsgType(IPCTNL_MSG_CT_NEW)
|
||||
.setProto(IPPROTO_TCP)
|
||||
.setRemotePort(offloadedPort)
|
||||
.build());
|
||||
verify(mBpfUpstream4Map).insertEntry(any(), any());
|
||||
verify(mBpfDownstream4Map).insertEntry(any(), any());
|
||||
clearInvocations(mBpfUpstream4Map, mBpfDownstream4Map);
|
||||
|
||||
for (final short port : NON_OFFLOADED_UPSTREAM_IPV4_TCP_PORTS) {
|
||||
mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_NEW, IPPROTO_TCP, port));
|
||||
mConsumer.accept(new TestConntrackEvent.Builder()
|
||||
.setMsgType(IPCTNL_MSG_CT_NEW)
|
||||
.setProto(IPPROTO_TCP)
|
||||
.setRemotePort(port)
|
||||
.build());
|
||||
verify(mBpfUpstream4Map, never()).insertEntry(any(), any());
|
||||
verify(mBpfDownstream4Map, never()).insertEntry(any(), any());
|
||||
|
||||
mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_DELETE, IPPROTO_TCP, port));
|
||||
mConsumer.accept(new TestConntrackEvent.Builder()
|
||||
.setMsgType(IPCTNL_MSG_CT_DELETE)
|
||||
.setProto(IPPROTO_TCP)
|
||||
.setRemotePort(port)
|
||||
.build());
|
||||
verify(mBpfUpstream4Map, never()).deleteEntry(any());
|
||||
verify(mBpfDownstream4Map, never()).deleteEntry(any());
|
||||
|
||||
mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_NEW, IPPROTO_UDP, port));
|
||||
mConsumer.accept(new TestConntrackEvent.Builder()
|
||||
.setMsgType(IPCTNL_MSG_CT_NEW)
|
||||
.setProto(IPPROTO_UDP)
|
||||
.setRemotePort(port)
|
||||
.build());
|
||||
verify(mBpfUpstream4Map).insertEntry(any(), any());
|
||||
verify(mBpfDownstream4Map).insertEntry(any(), any());
|
||||
clearInvocations(mBpfUpstream4Map, mBpfDownstream4Map);
|
||||
|
||||
mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_DELETE, IPPROTO_UDP, port));
|
||||
mConsumer.accept(new TestConntrackEvent.Builder()
|
||||
.setMsgType(IPCTNL_MSG_CT_DELETE)
|
||||
.setProto(IPPROTO_UDP)
|
||||
.setRemotePort(port)
|
||||
.build());
|
||||
verify(mBpfUpstream4Map).deleteEntry(any());
|
||||
verify(mBpfDownstream4Map).deleteEntry(any());
|
||||
clearInvocations(mBpfUpstream4Map, mBpfDownstream4Map);
|
||||
|
||||
Reference in New Issue
Block a user