Merge "Add bpf forwording packet count test"
This commit is contained in:
@@ -121,6 +121,7 @@ public class BpfCoordinator {
|
|||||||
private static final String TETHER_LIMIT_MAP_PATH = makeMapPath("limit");
|
private static final String TETHER_LIMIT_MAP_PATH = makeMapPath("limit");
|
||||||
private static final String TETHER_ERROR_MAP_PATH = makeMapPath("error");
|
private static final String TETHER_ERROR_MAP_PATH = makeMapPath("error");
|
||||||
private static final String TETHER_DEV_MAP_PATH = makeMapPath("dev");
|
private static final String TETHER_DEV_MAP_PATH = makeMapPath("dev");
|
||||||
|
private static final String DUMPSYS_RAWMAP_ARG_STATS = "--stats";
|
||||||
private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
|
private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
|
||||||
|
|
||||||
// Using "," as a separator is safe because base64 characters are [0-9a-zA-Z/=+].
|
// Using "," as a separator is safe because base64 characters are [0-9a-zA-Z/=+].
|
||||||
@@ -1088,14 +1089,14 @@ public class BpfCoordinator {
|
|||||||
return keyBase64Str + DUMP_BASE64_DELIMITER + valueBase64Str;
|
return keyBase64Str + DUMP_BASE64_DELIMITER + valueBase64Str;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dumpRawIpv4ForwardingRuleMap(
|
private <K extends Struct, V extends Struct> void dumpRawMap(BpfMap<K, V> map,
|
||||||
BpfMap<Tether4Key, Tether4Value> map, IndentingPrintWriter pw) throws ErrnoException {
|
IndentingPrintWriter pw) throws ErrnoException {
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
pw.println("No IPv4 support");
|
pw.println("No BPF support");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (map.isEmpty()) {
|
if (map.isEmpty()) {
|
||||||
pw.println("No rules");
|
pw.println("No entries");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
map.forEach((k, v) -> pw.println(bpfMapEntryToBase64String(k, v)));
|
map.forEach((k, v) -> pw.println(bpfMapEntryToBase64String(k, v)));
|
||||||
@@ -1112,9 +1113,17 @@ public class BpfCoordinator {
|
|||||||
// it is okay for now because this is used by test only and test is supposed to use
|
// it is okay for now because this is used by test only and test is supposed to use
|
||||||
// expected argument order.
|
// expected argument order.
|
||||||
// TODO: dump downstream4 map.
|
// TODO: dump downstream4 map.
|
||||||
|
if (CollectionUtils.contains(args, DUMPSYS_RAWMAP_ARG_STATS)) {
|
||||||
|
try (BpfMap<TetherStatsKey, TetherStatsValue> statsMap = mDeps.getBpfStatsMap()) {
|
||||||
|
dumpRawMap(statsMap, pw);
|
||||||
|
} catch (ErrnoException e) {
|
||||||
|
pw.println("Error dumping stats map: " + e);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (CollectionUtils.contains(args, DUMPSYS_RAWMAP_ARG_UPSTREAM4)) {
|
if (CollectionUtils.contains(args, DUMPSYS_RAWMAP_ARG_UPSTREAM4)) {
|
||||||
try (BpfMap<Tether4Key, Tether4Value> upstreamMap = mDeps.getBpfUpstream4Map()) {
|
try (BpfMap<Tether4Key, Tether4Value> upstreamMap = mDeps.getBpfUpstream4Map()) {
|
||||||
dumpRawIpv4ForwardingRuleMap(upstreamMap, pw);
|
dumpRawMap(upstreamMap, pw);
|
||||||
} catch (ErrnoException e) {
|
} catch (ErrnoException e) {
|
||||||
pw.println("Error dumping IPv4 map: " + e);
|
pw.println("Error dumping IPv4 map: " + e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,8 @@ import com.android.net.module.util.PacketBuilder;
|
|||||||
import com.android.net.module.util.Struct;
|
import com.android.net.module.util.Struct;
|
||||||
import com.android.net.module.util.bpf.Tether4Key;
|
import com.android.net.module.util.bpf.Tether4Key;
|
||||||
import com.android.net.module.util.bpf.Tether4Value;
|
import com.android.net.module.util.bpf.Tether4Value;
|
||||||
|
import com.android.net.module.util.bpf.TetherStatsKey;
|
||||||
|
import com.android.net.module.util.bpf.TetherStatsValue;
|
||||||
import com.android.net.module.util.structs.EthernetHeader;
|
import com.android.net.module.util.structs.EthernetHeader;
|
||||||
import com.android.net.module.util.structs.Icmpv6Header;
|
import com.android.net.module.util.structs.Icmpv6Header;
|
||||||
import com.android.net.module.util.structs.Ipv4Header;
|
import com.android.net.module.util.structs.Ipv4Header;
|
||||||
@@ -128,6 +130,13 @@ public class EthernetTetheringTest {
|
|||||||
// Kernel treats a confirmed UDP connection which active after two seconds as stream mode.
|
// Kernel treats a confirmed UDP connection which active after two seconds as stream mode.
|
||||||
// See upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5.
|
// See upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5.
|
||||||
private static final int UDP_STREAM_TS_MS = 2000;
|
private static final int UDP_STREAM_TS_MS = 2000;
|
||||||
|
// Per RX UDP packet size: iphdr (20) + udphdr (8) + payload (2) = 30 bytes.
|
||||||
|
private static final int RX_UDP_PACKET_SIZE = 30;
|
||||||
|
private static final int RX_UDP_PACKET_COUNT = 456;
|
||||||
|
// Per TX UDP packet size: ethhdr (14) + iphdr (20) + udphdr (8) + payload (2) = 44 bytes.
|
||||||
|
private static final int TX_UDP_PACKET_SIZE = 44;
|
||||||
|
private static final int TX_UDP_PACKET_COUNT = 123;
|
||||||
|
|
||||||
private static final LinkAddress TEST_IP4_ADDR = new LinkAddress("10.0.0.1/8");
|
private static final LinkAddress TEST_IP4_ADDR = new LinkAddress("10.0.0.1/8");
|
||||||
private static final LinkAddress TEST_IP6_ADDR = new LinkAddress("2001:db8:1::101/64");
|
private static final LinkAddress TEST_IP6_ADDR = new LinkAddress("2001:db8:1::101/64");
|
||||||
private static final InetAddress TEST_IP4_DNS = parseNumericAddress("8.8.8.8");
|
private static final InetAddress TEST_IP4_DNS = parseNumericAddress("8.8.8.8");
|
||||||
@@ -136,6 +145,7 @@ public class EthernetTetheringTest {
|
|||||||
ByteBuffer.wrap(new byte[] { (byte) 0x55, (byte) 0xaa });
|
ByteBuffer.wrap(new byte[] { (byte) 0x55, (byte) 0xaa });
|
||||||
|
|
||||||
private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap";
|
private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap";
|
||||||
|
private static final String DUMPSYS_RAWMAP_ARG_STATS = "--stats";
|
||||||
private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
|
private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
|
||||||
private static final String BASE64_DELIMITER = ",";
|
private static final String BASE64_DELIMITER = ",";
|
||||||
private static final String LINE_DELIMITER = "\\n";
|
private static final String LINE_DELIMITER = "\\n";
|
||||||
@@ -957,6 +967,7 @@ public class EthernetTetheringTest {
|
|||||||
return isExpectedUdpPacket(p, false /* hasEther */, PAYLOAD3);
|
return isExpectedUdpPacket(p, false /* hasEther */, PAYLOAD3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// [1] Verify IPv4 upstream rule map.
|
||||||
final HashMap<Tether4Key, Tether4Value> upstreamMap = pollRawMapFromDump(
|
final HashMap<Tether4Key, Tether4Value> upstreamMap = pollRawMapFromDump(
|
||||||
Tether4Key.class, Tether4Value.class, DUMPSYS_RAWMAP_ARG_UPSTREAM4);
|
Tether4Key.class, Tether4Value.class, DUMPSYS_RAWMAP_ARG_UPSTREAM4);
|
||||||
assertNotNull(upstreamMap);
|
assertNotNull(upstreamMap);
|
||||||
@@ -965,20 +976,60 @@ public class EthernetTetheringTest {
|
|||||||
final Map.Entry<Tether4Key, Tether4Value> rule =
|
final Map.Entry<Tether4Key, Tether4Value> rule =
|
||||||
upstreamMap.entrySet().iterator().next();
|
upstreamMap.entrySet().iterator().next();
|
||||||
|
|
||||||
final Tether4Key key = rule.getKey();
|
final Tether4Key upstream4Key = rule.getKey();
|
||||||
assertEquals(IPPROTO_UDP, key.l4proto);
|
assertEquals(IPPROTO_UDP, upstream4Key.l4proto);
|
||||||
assertTrue(Arrays.equals(tethered.ipv4Addr.getAddress(), key.src4));
|
assertTrue(Arrays.equals(tethered.ipv4Addr.getAddress(), upstream4Key.src4));
|
||||||
assertEquals(LOCAL_PORT, key.srcPort);
|
assertEquals(LOCAL_PORT, upstream4Key.srcPort);
|
||||||
assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(), key.dst4));
|
assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(), upstream4Key.dst4));
|
||||||
assertEquals(REMOTE_PORT, key.dstPort);
|
assertEquals(REMOTE_PORT, upstream4Key.dstPort);
|
||||||
|
|
||||||
final Tether4Value value = rule.getValue();
|
final Tether4Value upstream4Value = rule.getValue();
|
||||||
assertTrue(Arrays.equals(publicIp4Addr.getAddress(),
|
assertTrue(Arrays.equals(publicIp4Addr.getAddress(),
|
||||||
InetAddress.getByAddress(value.src46).getAddress()));
|
InetAddress.getByAddress(upstream4Value.src46).getAddress()));
|
||||||
assertEquals(LOCAL_PORT, value.srcPort);
|
assertEquals(LOCAL_PORT, upstream4Value.srcPort);
|
||||||
assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(),
|
assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(),
|
||||||
InetAddress.getByAddress(value.dst46).getAddress()));
|
InetAddress.getByAddress(upstream4Value.dst46).getAddress()));
|
||||||
assertEquals(REMOTE_PORT, value.dstPort);
|
assertEquals(REMOTE_PORT, upstream4Value.dstPort);
|
||||||
|
|
||||||
|
// [2] Verify stats map.
|
||||||
|
// Transmit packets on both direction for verifying stats. Because we only care the
|
||||||
|
// packet count in stats test, we just reuse the existing packets to increaes
|
||||||
|
// the packet count on both direction.
|
||||||
|
|
||||||
|
// Send packets on original direction.
|
||||||
|
for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) {
|
||||||
|
tester.verifyUpload(remote, originalPacket, p -> {
|
||||||
|
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
|
||||||
|
return isExpectedUdpPacket(p, false /* hasEther */, PAYLOAD);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send packets on reply direction.
|
||||||
|
for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) {
|
||||||
|
remote.verifyDownload(tester, replyPacket, p -> {
|
||||||
|
Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
|
||||||
|
return isExpectedUdpPacket(p, true/* hasEther */, PAYLOAD2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump stats map to verify.
|
||||||
|
final HashMap<TetherStatsKey, TetherStatsValue> statsMap = pollRawMapFromDump(
|
||||||
|
TetherStatsKey.class, TetherStatsValue.class, DUMPSYS_RAWMAP_ARG_STATS);
|
||||||
|
assertNotNull(statsMap);
|
||||||
|
assertEquals(1, statsMap.size());
|
||||||
|
|
||||||
|
final Map.Entry<TetherStatsKey, TetherStatsValue> stats =
|
||||||
|
statsMap.entrySet().iterator().next();
|
||||||
|
|
||||||
|
// TODO: verify the upstream index in TetherStatsKey.
|
||||||
|
|
||||||
|
final TetherStatsValue statsValue = stats.getValue();
|
||||||
|
assertEquals(RX_UDP_PACKET_COUNT, statsValue.rxPackets);
|
||||||
|
assertEquals(RX_UDP_PACKET_COUNT * RX_UDP_PACKET_SIZE, statsValue.rxBytes);
|
||||||
|
assertEquals(0, statsValue.rxErrors);
|
||||||
|
assertEquals(TX_UDP_PACKET_COUNT, statsValue.txPackets);
|
||||||
|
assertEquals(TX_UDP_PACKET_COUNT * TX_UDP_PACKET_SIZE, statsValue.txBytes);
|
||||||
|
assertEquals(0, statsValue.txErrors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user