Merge "Obtain the MTU from a socket to the destination" into main
This commit is contained in:
commit
f8732eb2ce
1 changed files with 47 additions and 13 deletions
|
|
@ -24,9 +24,12 @@ import static com.android.net.module.util.NetworkStackConstants.ICMP_HEADER_LEN;
|
|||
import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN;
|
||||
import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN;
|
||||
import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
|
||||
import static com.android.net.module.util.NetworkStackConstants.IPV6_MTU;
|
||||
import static com.android.net.module.util.NetworkStackConstants.IP_MTU;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.TargetApi;
|
||||
import android.net.InetAddresses;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties;
|
||||
|
|
@ -35,6 +38,7 @@ import android.net.RouteInfo;
|
|||
import android.net.TrafficStats;
|
||||
import android.net.shared.PrivateDnsConfig;
|
||||
import android.net.util.NetworkConstants;
|
||||
import android.os.Build;
|
||||
import android.os.SystemClock;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
|
|
@ -213,14 +217,10 @@ public class NetworkDiagnostics {
|
|||
mLinkProperties.addDnsServer(TEST_DNS6);
|
||||
}
|
||||
|
||||
final int lpMtu = mLinkProperties.getMtu();
|
||||
final int mtu = lpMtu > 0 ? lpMtu : ETHER_MTU;
|
||||
for (RouteInfo route : mLinkProperties.getRoutes()) {
|
||||
if (route.getType() == RouteInfo.RTN_UNICAST && route.hasGateway()) {
|
||||
InetAddress gateway = route.getGateway();
|
||||
// Use mtu in the route if exists. Otherwise, use the one in the link property.
|
||||
final int routeMtu = route.getMtu();
|
||||
prepareIcmpMeasurements(gateway, (routeMtu > 0) ? routeMtu : mtu);
|
||||
final InetAddress gateway = route.getGateway();
|
||||
prepareIcmpMeasurements(gateway);
|
||||
if (route.isIPv6Default()) {
|
||||
prepareExplicitSourceIcmpMeasurements(gateway);
|
||||
}
|
||||
|
|
@ -228,7 +228,7 @@ public class NetworkDiagnostics {
|
|||
}
|
||||
|
||||
for (InetAddress nameserver : mLinkProperties.getDnsServers()) {
|
||||
prepareIcmpMeasurements(nameserver, mtu);
|
||||
prepareIcmpMeasurements(nameserver);
|
||||
prepareDnsMeasurement(nameserver);
|
||||
|
||||
// Unlike the DnsResolver which doesn't do certificate validation in opportunistic mode,
|
||||
|
|
@ -285,24 +285,29 @@ public class NetworkDiagnostics {
|
|||
// calculation.
|
||||
if (addr instanceof Inet6Address) {
|
||||
return IPV6_HEADER_LEN + ICMP_HEADER_LEN;
|
||||
} else {
|
||||
return IPV4_HEADER_MIN_LEN + ICMP_HEADER_LEN;
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
Log.e(TAG, "Create InetAddress fail(" + target + "): " + e);
|
||||
throw new AssertionError("Create InetAddress fail(" + target + ")", e);
|
||||
}
|
||||
|
||||
return IPV4_HEADER_MIN_LEN + ICMP_HEADER_LEN;
|
||||
}
|
||||
|
||||
private void prepareIcmpMeasurements(@NonNull InetAddress target, int targetNetworkMtu) {
|
||||
private void prepareIcmpMeasurements(@NonNull InetAddress target) {
|
||||
int mtu = getMtuForTarget(target);
|
||||
// If getMtuForTarget fails, it doesn't matter what mtu is used because connect can't
|
||||
// succeed anyway
|
||||
if (mtu <= 0) mtu = mLinkProperties.getMtu();
|
||||
if (mtu <= 0) mtu = ETHER_MTU;
|
||||
// Test with different size payload ICMP.
|
||||
// 1. Test with 0 payload.
|
||||
addPayloadIcmpMeasurement(target, 0);
|
||||
final int header = getHeaderLen(target);
|
||||
// 2. Test with full size MTU.
|
||||
addPayloadIcmpMeasurement(target, targetNetworkMtu - header);
|
||||
addPayloadIcmpMeasurement(target, mtu - header);
|
||||
// 3. If v6, make another measurement with the full v6 min MTU, unless that's what
|
||||
// was done above.
|
||||
if ((target instanceof Inet6Address) && (targetNetworkMtu != IPV6_MIN_MTU)) {
|
||||
if ((target instanceof Inet6Address) && (mtu != IPV6_MIN_MTU)) {
|
||||
addPayloadIcmpMeasurement(target, IPV6_MIN_MTU - header);
|
||||
}
|
||||
}
|
||||
|
|
@ -321,6 +326,35 @@ public class NetworkDiagnostics {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a socket to the target address and return the mtu from that socket
|
||||
*
|
||||
* If the MTU can't be obtained for some reason (e.g. the target is unreachable) this will
|
||||
* return -1.
|
||||
*
|
||||
* @param target the destination address
|
||||
* @return the mtu to that destination, or -1
|
||||
*/
|
||||
// getsockoptInt is S+, but this service code and only installs on S, so it's safe to ignore
|
||||
// the lint warnings by using @TargetApi.
|
||||
@TargetApi(Build.VERSION_CODES.S)
|
||||
private int getMtuForTarget(InetAddress target) {
|
||||
final int family = target instanceof Inet4Address ? AF_INET : AF_INET6;
|
||||
try {
|
||||
final FileDescriptor socket = Os.socket(family, SOCK_DGRAM, 0);
|
||||
mNetwork.bindSocket(socket);
|
||||
Os.connect(socket, target, 0);
|
||||
if (family == AF_INET) {
|
||||
return Os.getsockoptInt(socket, IPPROTO_IP, IP_MTU);
|
||||
} else {
|
||||
return Os.getsockoptInt(socket, IPPROTO_IPV6, IPV6_MTU);
|
||||
}
|
||||
} catch (ErrnoException | IOException e) {
|
||||
Log.e(TAG, "Can't get MTU for destination " + target, e);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareExplicitSourceIcmpMeasurements(InetAddress target) {
|
||||
for (LinkAddress l : mLinkProperties.getLinkAddresses()) {
|
||||
InetAddress source = l.getAddress();
|
||||
|
|
|
|||
Loading…
Reference in a new issue