Deprecate IPv6 prefixes no longer in use.

Bug: 30298058
Change-Id: I0fa9ece9b2fb07214971a91b77f5b07972d83bb6
This commit is contained in:
Erik Kline
2016-08-01 16:15:05 +09:00
parent a2f247e6a6
commit 354607f2ac
2 changed files with 110 additions and 37 deletions

View File

@@ -176,9 +176,21 @@ class IPv6TetheringInterfaceServices {
private void updateRaParams(RaParams params) { private void updateRaParams(RaParams params) {
if (mRaDaemon != null) { if (mRaDaemon != null) {
HashSet<IpPrefix> deprecated = null;
if (mLastRaParams != null) {
deprecated = new HashSet<>();
for (IpPrefix ipp : mLastRaParams.prefixes) {
if (params == null || !params.prefixes.contains(ipp)) {
deprecated.add(ipp);
}
}
}
// Currently, we send spurious RAs (5) whenever there's any update. // Currently, we send spurious RAs (5) whenever there's any update.
// TODO: Compare params with mLastParams to avoid spurious updates. // TODO: Compare params with mLastParams to avoid spurious updates.
mRaDaemon.buildNewRa(params); mRaDaemon.buildNewRa(params, deprecated);
} }
mLastRaParams = params; mLastRaParams = params;

View File

@@ -45,7 +45,9 @@ import java.nio.BufferOverflowException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@@ -109,6 +111,11 @@ public class RouterAdvertisementDaemon {
private final byte[] mRA = new byte[IPV6_MIN_MTU]; private final byte[] mRA = new byte[IPV6_MIN_MTU];
@GuardedBy("mLock") @GuardedBy("mLock")
private int mRaLength; private int mRaLength;
@GuardedBy("mLock")
private final HashMap<IpPrefix, Integer> mDeprecatedPrefixes;
@GuardedBy("mLock")
private RaParams mRaParams;
private volatile FileDescriptor mSocket; private volatile FileDescriptor mSocket;
private volatile MulticastTransmitter mMulticastTransmitter; private volatile MulticastTransmitter mMulticastTransmitter;
@@ -141,45 +148,29 @@ public class RouterAdvertisementDaemon {
mIfIndex = ifindex; mIfIndex = ifindex;
mHwAddr = hwaddr; mHwAddr = hwaddr;
mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mIfIndex), 0); mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mIfIndex), 0);
mDeprecatedPrefixes = new HashMap<>();
} }
public void buildNewRa(RaParams params) { public void buildNewRa(RaParams params, HashSet<IpPrefix> newlyDeprecated) {
if (newlyDeprecated != null) {
synchronized (mLock) {
for (IpPrefix ipp : newlyDeprecated) {
mDeprecatedPrefixes.put(ipp, MAX_URGENT_RTR_ADVERTISEMENTS);
}
}
}
// TODO: Send MAX_URGENT_RTR_ADVERTISEMENTS zero router lifetime RAs,
// iff. we have already sent an RA.
if (params == null || params.prefixes.isEmpty()) { if (params == null || params.prefixes.isEmpty()) {
// No RA to be served at this time. // No RA to be served at this time.
clearRa(); clearRa();
return; return;
} }
if (params.mtu < IPV6_MIN_MTU) {
params.mtu = IPV6_MIN_MTU;
}
final ByteBuffer ra = ByteBuffer.wrap(mRA);
ra.order(ByteOrder.BIG_ENDIAN);
synchronized (mLock) { synchronized (mLock) {
try { mRaParams = params;
putHeader(ra, params.hasDefaultRoute); assembleRa();
putSlla(ra, mHwAddr);
// https://tools.ietf.org/html/rfc5175#section-4 says:
//
// "MUST NOT be added to a Router Advertisement message
// if no flags in the option are set."
//
// putExpandedFlagsOption(ra);
putMtu(ra, params.mtu);
for (IpPrefix ipp : params.prefixes) {
putPio(ra, ipp);
}
if (params.dnses.size() > 0) {
putRdnss(ra, params.dnses);
}
mRaLength = ra.position();
} catch (BufferOverflowException e) {
Log.e(TAG, "Could not construct new RA: " + e);
mRaLength = 0;
return;
}
} }
maybeNotifyMulticastTransmitter(); maybeNotifyMulticastTransmitter();
@@ -216,6 +207,64 @@ public class RouterAdvertisementDaemon {
} }
} }
private void assembleRa() {
final ByteBuffer ra = ByteBuffer.wrap(mRA);
ra.order(ByteOrder.BIG_ENDIAN);
synchronized (mLock) {
try {
putHeader(ra, mRaParams.hasDefaultRoute);
putSlla(ra, mHwAddr);
// https://tools.ietf.org/html/rfc5175#section-4 says:
//
// "MUST NOT be added to a Router Advertisement message
// if no flags in the option are set."
//
// putExpandedFlagsOption(ra);
putMtu(ra, mRaParams.mtu);
for (IpPrefix ipp : mRaParams.prefixes) {
putPio(ra, ipp, DEFAULT_LIFETIME, DEFAULT_LIFETIME);
mDeprecatedPrefixes.remove(ipp);
}
for (IpPrefix ipp : mDeprecatedPrefixes.keySet()) {
putPio(ra, ipp, 0, 0);
}
if (mRaParams.dnses.size() > 0) {
putRdnss(ra, mRaParams.dnses);
}
mRaLength = ra.position();
} catch (BufferOverflowException e) {
Log.e(TAG, "Could not construct new RA: " + e);
mRaLength = 0;
return;
}
}
}
private int decrementDeprecatedPrefixes() {
int removed = 0;
synchronized (mLock) {
for (Map.Entry<IpPrefix, Integer> kv : mDeprecatedPrefixes.entrySet()) {
if (kv.getValue() == 0) {
mDeprecatedPrefixes.remove(kv.getKey());
removed++;
} else {
kv.setValue(kv.getValue() - 1);
}
}
}
return removed;
}
private void maybeNotifyMulticastTransmitter() { private void maybeNotifyMulticastTransmitter() {
final MulticastTransmitter m = mMulticastTransmitter; final MulticastTransmitter m = mMulticastTransmitter;
if (m != null) { if (m != null) {
@@ -325,10 +374,11 @@ public class RouterAdvertisementDaemon {
ra.put(ND_OPTION_MTU) ra.put(ND_OPTION_MTU)
.put(MTU_NUM_8OCTETS) .put(MTU_NUM_8OCTETS)
.putShort(asShort(0)) .putShort(asShort(0))
.putInt(mtu); .putInt((mtu < IPV6_MIN_MTU) ? IPV6_MIN_MTU : mtu);
} }
private static void putPio(ByteBuffer ra, IpPrefix ipp) { private static void putPio(ByteBuffer ra, IpPrefix ipp,
int validTime, int preferredTime) {
/** /**
Prefix Information Prefix Information
@@ -359,13 +409,17 @@ public class RouterAdvertisementDaemon {
final byte ND_OPTION_PIO = 3; final byte ND_OPTION_PIO = 3;
final byte PIO_NUM_8OCTETS = 4; final byte PIO_NUM_8OCTETS = 4;
if (validTime < 0) validTime = 0;
if (preferredTime < 0) preferredTime = 0;
if (preferredTime > validTime) preferredTime = validTime;
final byte[] addr = ipp.getAddress().getAddress(); final byte[] addr = ipp.getAddress().getAddress();
ra.put(ND_OPTION_PIO) ra.put(ND_OPTION_PIO)
.put(PIO_NUM_8OCTETS) .put(PIO_NUM_8OCTETS)
.put(asByte(prefixLength)) .put(asByte(prefixLength))
.put(asByte(0xc0)) // L&A set .put(asByte(0xc0)) /* L & A set */
.putInt(DEFAULT_LIFETIME) .putInt(validTime)
.putInt(DEFAULT_LIFETIME) .putInt(preferredTime)
.putInt(0) .putInt(0)
.put(addr); .put(addr);
} }
@@ -547,6 +601,11 @@ public class RouterAdvertisementDaemon {
} }
maybeSendRA(mAllNodes); maybeSendRA(mAllNodes);
if (decrementDeprecatedPrefixes() > 0) {
// At least one deprecated PIO has been removed;
// reassemble the RA.
assembleRa();
}
} }
} }
@@ -560,15 +619,17 @@ public class RouterAdvertisementDaemon {
} }
private int getNextMulticastTransmitDelaySec() { private int getNextMulticastTransmitDelaySec() {
int countDeprecatedPrefixes = 0;
synchronized (mLock) { synchronized (mLock) {
if (mRaLength < MIN_RA_HEADER_SIZE) { if (mRaLength < MIN_RA_HEADER_SIZE) {
// No actual RA to send; just sleep for 1 day. // No actual RA to send; just sleep for 1 day.
return DAY_IN_SECONDS; return DAY_IN_SECONDS;
} }
countDeprecatedPrefixes = mDeprecatedPrefixes.size();
} }
final int urgentPending = mUrgentAnnouncements.getAndDecrement(); final int urgentPending = mUrgentAnnouncements.getAndDecrement();
if (urgentPending > 0) { if (urgentPending > 0 || countDeprecatedPrefixes > 0) {
return MIN_DELAY_BETWEEN_RAS_SEC; return MIN_DELAY_BETWEEN_RAS_SEC;
} }