Generalize ip address handling in tether4Value bpf structures

Updated Tether4Value.java to utilize
java.net.InetAddress for relevant IP address fields.
These fields are correspondingly annotated with
Type.IpAddress for BPF map interactions.

Bug: 392509494
Test: atest TetheringTests
Flag: EXEMPT refactor
Change-Id: I6b5b1e176a47b55ad7482be15e4e2d8ee95ab1d1
This commit is contained in:
Sarup Dalwani 2025-04-22 19:00:32 +00:00 • committed by Maciej Żenczykowski
commit cdd31d8bf3
4 changed files with 36 additions and 79 deletions

View file

@ -1071,7 +1071,7 @@ public class BpfCoordinator {
}
});
mBpfCoordinatorShim.tetherOffloadRuleForEach(DOWNSTREAM, (k, v) -> {
if (Arrays.equals(v.dst46, toIpv4MappedAddressBytes(clientAddr))) {
if (Objects.equals(v.dst46, clientAddr)) {
deleteDownstreamRuleKeys.add(k);
upstreamIndiceSet.add((int) k.iif);
}
@ -1560,20 +1560,15 @@ public class BpfCoordinator {
Tether4Key key, Tether4Value value) {
final String src4, public4, dst4;
final int publicPort;
try {
src4 = key.src4.getHostAddress();
if (downstream) {
public4 = key.dst4.getHostAddress();
publicPort = key.dstPort;
} else {
public4 = InetAddress.getByAddress(value.src46).getHostAddress();
publicPort = value.srcPort;
}
dst4 = InetAddress.getByAddress(value.dst46).getHostAddress();
} catch (UnknownHostException impossible) {
throw new AssertionError("IP address array not valid IPv4 address!");
src4 = key.src4.getHostAddress();
if (downstream) {
public4 = key.dst4.getHostAddress();
publicPort = key.dstPort;
} else {
public4 = value.src46.getHostAddress();
publicPort = value.srcPort;
}
dst4 = value.dst46.getHostAddress();
final String ageStr = (value.lastUsed == 0) ? "-"
: String.format("%dms", (now - value.lastUsed) / 1_000_000);
return String.format("%s [%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d [%s] %d %s",
@ -2042,20 +2037,6 @@ public class BpfCoordinator {
return null;
}
@NonNull
@VisibleForTesting
static 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;
}
// TODO: parse CTA_PROTOINFO of conntrack event in ConntrackMonitor. For TCP, only add rules
// while TCP status is established.
@VisibleForTesting
@ -2139,8 +2120,7 @@ public class BpfCoordinator {
return new Tether4Value(upstreamInfo.ifIndex,
NULL_MAC_ADDRESS /* ethDstMac (rawip) */,
NULL_MAC_ADDRESS /* ethSrcMac (rawip) */, ETH_P_IP,
upstreamInfo.mtu, toIpv4MappedAddressBytes(e.tupleReply.dstIp),
toIpv4MappedAddressBytes(e.tupleReply.srcIp), e.tupleReply.dstPort,
upstreamInfo.mtu, e.tupleReply.dstIp, e.tupleReply.srcIp, e.tupleReply.dstPort,
e.tupleReply.srcPort, 0 /* lastUsed, filled by bpf prog only */);
}
@ -2149,8 +2129,7 @@ public class BpfCoordinator {
@NonNull ClientInfo c, @NonNull UpstreamInfo upstreamInfo) {
return new Tether4Value(c.downstreamIfindex,
c.clientMac, c.downstreamMac, ETH_P_IP, upstreamInfo.mtu,
toIpv4MappedAddressBytes(e.tupleOrig.dstIp),
toIpv4MappedAddressBytes(e.tupleOrig.srcIp),
e.tupleOrig.dstIp, e.tupleOrig.srcIp,
e.tupleOrig.dstPort, e.tupleOrig.srcPort,
0 /* lastUsed, filled by bpf prog only */);
}
@ -2475,17 +2454,6 @@ public class BpfCoordinator {
return Math.max(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS, configInterval);
}
@Nullable
private Inet4Address parseIPv4Address(byte[] addrBytes) {
try {
final InetAddress ia = Inet4Address.getByAddress(addrBytes);
if (ia instanceof Inet4Address) return (Inet4Address) ia;
} catch (UnknownHostException e) {
mLog.e("Failed to parse IPv4 address: " + e);
}
return null;
}
// Update CTA_TUPLE_ORIG timeout for a given conntrack entry. Note that there will also be
// coming a conntrack event to notify updated timeout.
private void updateConntrackTimeout(byte proto, Inet4Address src4, short srcPort,
@ -2552,9 +2520,8 @@ public class BpfCoordinator {
// which is opposite direction for downstream map value.
mBpfCoordinatorShim.tetherOffloadRuleForEach(DOWNSTREAM, (k, v) -> {
if ((now - v.lastUsed) / 1_000_000 < CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS) {
updateConntrackTimeout((byte) k.l4proto,
parseIPv4Address(v.dst46), (short) v.dstPort,
parseIPv4Address(v.src46), (short) v.srcPort);
updateConntrackTimeout((byte) k.l4proto, (Inet4Address) v.dst46, (short) v.dstPort,
(Inet4Address) v.src46, (short) v.srcPort);
}
});
}

View file

@ -1026,11 +1026,9 @@ public class EthernetTetheringTest extends EthernetTetheringTestBase {
assertEquals(REMOTE_PORT, upstream4Key.dstPort);
final Tether4Value upstream4Value = rule.getValue();
assertTrue(Arrays.equals(tetheringUpstreamIp.getAddress(),
InetAddress.getByAddress(upstream4Value.src46).getAddress()));
assertEquals(tetheringUpstreamIp, upstream4Value.src46);
assertEquals(LOCAL_PORT, upstream4Value.srcPort);
assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(),
InetAddress.getByAddress(upstream4Value.dst46).getAddress()));
assertEquals(REMOTE_IP4_ADDR, upstream4Value.dst46);
assertEquals(REMOTE_PORT, upstream4Value.dstPort);
// [2] Verify stats map.

View file

@ -57,7 +57,6 @@ 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;
@ -351,8 +350,8 @@ public class BpfCoordinatorTest {
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 InetAddress mSrc46 = PUBLIC_ADDR;
private InetAddress mDst46 = REMOTE_ADDR;
private int mSrcPort = PUBLIC_PORT;
private int mDstPort = REMOTE_PORT;
private long mLastUsed = 0;
@ -376,8 +375,8 @@ public class BpfCoordinatorTest {
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 InetAddress mSrc46 = REMOTE_ADDR;
private InetAddress mDst46 = PRIVATE_ADDR;
private int mSrcPort = REMOTE_PORT;
private int mDstPort = PRIVATE_PORT;
private long mLastUsed = 0;
@ -2445,8 +2444,7 @@ public class BpfCoordinatorTest {
return new Tether4Value(UPSTREAM_IFINDEX,
MacAddress.ALL_ZEROS_ADDRESS /* ethDstMac (rawip) */,
MacAddress.ALL_ZEROS_ADDRESS /* ethSrcMac (rawip) */, ETH_P_IP,
NetworkStackConstants.ETHER_MTU, toIpv4MappedAddressBytes(PUBLIC_ADDR),
toIpv4MappedAddressBytes(REMOTE_ADDR), publicPort, REMOTE_PORT,
NetworkStackConstants.ETHER_MTU, PUBLIC_ADDR, REMOTE_ADDR, publicPort, REMOTE_PORT,
0 /* lastUsed */);
}
@ -2455,8 +2453,8 @@ public class BpfCoordinatorTest {
@NonNull final MacAddress clientMac, @NonNull final MacAddress downstreamMac,
@NonNull final Inet4Address privateAddr, final short privatePort) {
return new Tether4Value(downstreamIfindex, clientMac, downstreamMac,
ETH_P_IP, NetworkStackConstants.ETHER_MTU, toIpv4MappedAddressBytes(REMOTE_ADDR),
toIpv4MappedAddressBytes(privateAddr), REMOTE_PORT, privatePort, 0 /* lastUsed */);
ETH_P_IP, NetworkStackConstants.ETHER_MTU, REMOTE_ADDR, privateAddr, REMOTE_PORT,
privatePort, 0 /* lastUsed */);
}
@NonNull

View file

@ -21,11 +21,8 @@ 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;
/** Value type for downstream & upstream IPv4 forwarding maps. */
@ -44,11 +41,11 @@ public class Tether4Value extends Struct {
@Field(order = 4, type = Type.U16)
public final int pmtu;
@Field(order = 5, type = Type.ByteArray, arraysize = 16)
public final byte[] src46;
@Field(order = 5, type = Type.IpAddress)
public final InetAddress src46;
@Field(order = 6, type = Type.ByteArray, arraysize = 16)
public final byte[] dst46;
@Field(order = 6, type = Type.IpAddress)
public final InetAddress dst46;
@Field(order = 7, type = Type.UBE16)
public final int srcPort;
@ -62,10 +59,12 @@ public class Tether4Value extends Struct {
public Tether4Value(final int oif, @NonNull final MacAddress ethDstMac,
@NonNull final MacAddress ethSrcMac, final int ethProto, final int pmtu,
final byte[] src46, final byte[] dst46, final int srcPort,
@NonNull InetAddress src46, @NonNull InetAddress dst46, final int srcPort,
final int dstPort, final long lastUsed) {
Objects.requireNonNull(ethDstMac);
Objects.requireNonNull(ethSrcMac);
Objects.requireNonNull(src46);
Objects.requireNonNull(dst46);
this.oif = oif;
this.ethDstMac = ethDstMac;
@ -81,17 +80,12 @@ public class Tether4Value extends Struct {
@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 "Invalid IP address" + e;
}
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, src46, dst46,
Short.toUnsignedInt((short) srcPort), Short.toUnsignedInt((short) dstPort),
lastUsed);
}
}