Merge "IpManager: define InitialConfiguration"
This commit is contained in:
@@ -16,6 +16,15 @@
|
||||
|
||||
package android.net;
|
||||
|
||||
import static android.system.OsConstants.IFA_F_DADFAILED;
|
||||
import static android.system.OsConstants.IFA_F_DEPRECATED;
|
||||
import static android.system.OsConstants.IFA_F_OPTIMISTIC;
|
||||
import static android.system.OsConstants.IFA_F_TENTATIVE;
|
||||
import static android.system.OsConstants.RT_SCOPE_HOST;
|
||||
import static android.system.OsConstants.RT_SCOPE_LINK;
|
||||
import static android.system.OsConstants.RT_SCOPE_SITE;
|
||||
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Pair;
|
||||
@@ -26,15 +35,6 @@ import java.net.InetAddress;
|
||||
import java.net.InterfaceAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import static android.system.OsConstants.IFA_F_DADFAILED;
|
||||
import static android.system.OsConstants.IFA_F_DEPRECATED;
|
||||
import static android.system.OsConstants.IFA_F_OPTIMISTIC;
|
||||
import static android.system.OsConstants.IFA_F_TENTATIVE;
|
||||
import static android.system.OsConstants.RT_SCOPE_HOST;
|
||||
import static android.system.OsConstants.RT_SCOPE_LINK;
|
||||
import static android.system.OsConstants.RT_SCOPE_SITE;
|
||||
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
|
||||
|
||||
/**
|
||||
* Identifies an IP address on a network link.
|
||||
*
|
||||
@@ -101,7 +101,7 @@ public class LinkAddress implements Parcelable {
|
||||
* Per RFC 4193 section 8, fc00::/7 identifies these addresses.
|
||||
*/
|
||||
private boolean isIPv6ULA() {
|
||||
if (address != null && address instanceof Inet6Address) {
|
||||
if (address instanceof Inet6Address) {
|
||||
byte[] bytes = address.getAddress();
|
||||
return ((bytes[0] & (byte)0xfe) == (byte)0xfc);
|
||||
}
|
||||
|
||||
@@ -42,10 +42,13 @@ public final class IpManagerEvent implements Parcelable {
|
||||
/** @hide */ public static final int ERROR_STARTING_IPV6 = 5;
|
||||
/** @hide */ public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6;
|
||||
|
||||
/** @hide */ public static final int ERROR_INVALID_PROVISIONING = 7;
|
||||
|
||||
/** {@hide} */
|
||||
@IntDef(value = {
|
||||
PROVISIONING_OK, PROVISIONING_FAIL, COMPLETE_LIFECYCLE,
|
||||
ERROR_STARTING_IPV4, ERROR_STARTING_IPV6, ERROR_STARTING_IPREACHABILITYMONITOR,
|
||||
ERROR_INVALID_PROVISIONING,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface EventType {}
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.content.Context;
|
||||
import android.net.DhcpResults;
|
||||
import android.net.INetd;
|
||||
import android.net.InterfaceConfiguration;
|
||||
import android.net.IpPrefix;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties.ProvisioningChange;
|
||||
import android.net.LinkProperties;
|
||||
@@ -35,6 +36,7 @@ import android.net.dhcp.DhcpClient;
|
||||
import android.net.metrics.IpConnectivityLog;
|
||||
import android.net.metrics.IpManagerEvent;
|
||||
import android.net.util.MultinetworkPolicyTracker;
|
||||
import android.net.util.NetworkConstants;
|
||||
import android.net.util.SharedLog;
|
||||
import android.os.INetworkManagementService;
|
||||
import android.os.Message;
|
||||
@@ -51,17 +53,25 @@ import android.util.SparseArray;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.internal.util.IState;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.internal.util.State;
|
||||
import com.android.internal.util.StateMachine;
|
||||
import com.android.server.net.NetlinkTracker;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
/**
|
||||
@@ -308,6 +318,11 @@ public class IpManager extends StateMachine {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
|
||||
mConfig.mInitialConfig = initialConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
|
||||
mConfig.mStaticIpConfig = staticConfig;
|
||||
return this;
|
||||
@@ -342,18 +357,20 @@ public class IpManager extends StateMachine {
|
||||
/* package */ boolean mEnableIPv6 = true;
|
||||
/* package */ boolean mUsingIpReachabilityMonitor = true;
|
||||
/* package */ int mRequestedPreDhcpActionMs;
|
||||
/* package */ InitialConfiguration mInitialConfig;
|
||||
/* package */ StaticIpConfiguration mStaticIpConfig;
|
||||
/* package */ ApfCapabilities mApfCapabilities;
|
||||
/* package */ int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
|
||||
/* package */ int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
|
||||
|
||||
public ProvisioningConfiguration() {}
|
||||
public ProvisioningConfiguration() {} // used by Builder
|
||||
|
||||
public ProvisioningConfiguration(ProvisioningConfiguration other) {
|
||||
mEnableIPv4 = other.mEnableIPv4;
|
||||
mEnableIPv6 = other.mEnableIPv6;
|
||||
mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
|
||||
mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs;
|
||||
mInitialConfig = InitialConfiguration.copy(other.mInitialConfig);
|
||||
mStaticIpConfig = other.mStaticIpConfig;
|
||||
mApfCapabilities = other.mApfCapabilities;
|
||||
mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
|
||||
@@ -366,12 +383,124 @@ public class IpManager extends StateMachine {
|
||||
.add("mEnableIPv6: " + mEnableIPv6)
|
||||
.add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
|
||||
.add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs)
|
||||
.add("mInitialConfig: " + mInitialConfig)
|
||||
.add("mStaticIpConfig: " + mStaticIpConfig)
|
||||
.add("mApfCapabilities: " + mApfCapabilities)
|
||||
.add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
|
||||
.add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
|
||||
.toString();
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return (mInitialConfig == null) || mInitialConfig.isValid();
|
||||
}
|
||||
}
|
||||
|
||||
public static class InitialConfiguration {
|
||||
public final Set<LinkAddress> ipAddresses = new HashSet<>();
|
||||
public final Set<IpPrefix> directlyConnectedRoutes = new HashSet<>();
|
||||
public final Set<InetAddress> dnsServers = new HashSet<>();
|
||||
public Inet4Address gateway; // WiFi legacy behavior with static ipv4 config
|
||||
|
||||
public static InitialConfiguration copy(InitialConfiguration config) {
|
||||
if (config == null) {
|
||||
return null;
|
||||
}
|
||||
InitialConfiguration configCopy = new InitialConfiguration();
|
||||
configCopy.ipAddresses.addAll(config.ipAddresses);
|
||||
configCopy.directlyConnectedRoutes.addAll(config.directlyConnectedRoutes);
|
||||
configCopy.dnsServers.addAll(config.dnsServers);
|
||||
return configCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"InitialConfiguration(IPs: {%s}, prefixes: {%s}, DNS: {%s}, v4 gateway: %s)",
|
||||
join(", ", ipAddresses), join(", ", directlyConnectedRoutes),
|
||||
join(", ", dnsServers), gateway);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
// For every IP address, there must be at least one prefix containing that address.
|
||||
for (LinkAddress addr : ipAddresses) {
|
||||
if (!any(directlyConnectedRoutes, (p) -> p.contains(addr.getAddress()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// For every dns server, there must be at least one prefix containing that address.
|
||||
for (InetAddress addr : dnsServers) {
|
||||
if (!any(directlyConnectedRoutes, (p) -> p.contains(addr))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// All IPv6 LinkAddresses have an RFC7421-suitable prefix length
|
||||
// (read: compliant with RFC4291#section2.5.4).
|
||||
if (any(ipAddresses, not(InitialConfiguration::isPrefixLengthCompliant))) {
|
||||
return false;
|
||||
}
|
||||
// If directlyConnectedRoutes contains an IPv6 default route
|
||||
// then ipAddresses MUST contain at least one non-ULA GUA.
|
||||
if (any(directlyConnectedRoutes, InitialConfiguration::isIPv6DefaultRoute)
|
||||
&& all(ipAddresses, not(InitialConfiguration::isIPv6GUA))) {
|
||||
return false;
|
||||
}
|
||||
// The prefix length of routes in directlyConnectedRoutes be within reasonable
|
||||
// bounds for IPv6: /48-/64 just as we’d accept in RIOs.
|
||||
if (any(directlyConnectedRoutes, not(InitialConfiguration::isPrefixLengthCompliant))) {
|
||||
return false;
|
||||
}
|
||||
// There no more than one IPv4 address
|
||||
if (ipAddresses.stream().filter(Inet4Address.class::isInstance).count() > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isPrefixLengthCompliant(LinkAddress addr) {
|
||||
return (addr.getAddress() instanceof Inet4Address)
|
||||
|| isCompliantIPv6PrefixLength(addr.getPrefixLength());
|
||||
}
|
||||
|
||||
private static boolean isPrefixLengthCompliant(IpPrefix prefix) {
|
||||
return (prefix.getAddress() instanceof Inet4Address)
|
||||
|| isCompliantIPv6PrefixLength(prefix.getPrefixLength());
|
||||
}
|
||||
|
||||
private static boolean isCompliantIPv6PrefixLength(int prefixLength) {
|
||||
return (NetworkConstants.RFC6177_MIN_PREFIX_LENGTH <= prefixLength)
|
||||
&& (prefixLength <= NetworkConstants.RFC7421_PREFIX_LENGTH);
|
||||
}
|
||||
|
||||
private static boolean isIPv6DefaultRoute(IpPrefix prefix) {
|
||||
return prefix.getAddress().equals(Inet6Address.ANY);
|
||||
}
|
||||
|
||||
private static boolean isIPv6GUA(LinkAddress addr) {
|
||||
return (addr.getAddress() instanceof Inet6Address) && addr.isGlobalPreferred();
|
||||
}
|
||||
|
||||
private static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
|
||||
for (T t : coll) {
|
||||
if (fn.test(t)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
|
||||
return !any(coll, not(fn));
|
||||
}
|
||||
|
||||
private static <T> Predicate<T> not(Predicate<T> fn) {
|
||||
return (t) -> !fn.test(t);
|
||||
}
|
||||
|
||||
private static <T> String join(String delimiter, Collection<T> coll) {
|
||||
return coll.stream().map(Object::toString).collect(Collectors.joining(delimiter));
|
||||
}
|
||||
}
|
||||
|
||||
public static final String DUMP_ARG = "ipmanager";
|
||||
@@ -436,8 +565,7 @@ public class IpManager extends StateMachine {
|
||||
private boolean mMulticastFiltering;
|
||||
private long mStartTimeMillis;
|
||||
|
||||
public IpManager(Context context, String ifName, Callback callback)
|
||||
throws IllegalArgumentException {
|
||||
public IpManager(Context context, String ifName, Callback callback) {
|
||||
this(context, ifName, callback, INetworkManagementService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)));
|
||||
}
|
||||
@@ -446,7 +574,7 @@ public class IpManager extends StateMachine {
|
||||
* An expanded constructor, useful for dependency injection.
|
||||
*/
|
||||
public IpManager(Context context, String ifName, Callback callback,
|
||||
INetworkManagementService nwService) throws IllegalArgumentException {
|
||||
INetworkManagementService nwService) {
|
||||
super(IpManager.class.getSimpleName() + "." + ifName);
|
||||
mTag = getName();
|
||||
|
||||
@@ -563,6 +691,11 @@ public class IpManager extends StateMachine {
|
||||
}
|
||||
|
||||
public void startProvisioning(ProvisioningConfiguration req) {
|
||||
if (!req.isValid()) {
|
||||
doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
|
||||
return;
|
||||
}
|
||||
|
||||
getNetworkInterface();
|
||||
|
||||
mCallback.setNeighborDiscoveryOffload(true);
|
||||
|
||||
@@ -102,6 +102,7 @@ public final class NetworkConstants {
|
||||
public static final int IPV6_ADDR_LEN = 16;
|
||||
public static final int IPV6_MIN_MTU = 1280;
|
||||
public static final int RFC7421_PREFIX_LENGTH = 64;
|
||||
public static final int RFC6177_MIN_PREFIX_LENGTH = 48;
|
||||
|
||||
/**
|
||||
* ICMPv6 constants.
|
||||
|
||||
@@ -16,11 +16,26 @@
|
||||
|
||||
package android.net.ip;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.timeout;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.net.IpPrefix;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.ip.IpManager.Callback;
|
||||
import android.net.ip.IpManager.InitialConfiguration;
|
||||
import android.net.ip.IpManager.ProvisioningConfiguration;
|
||||
import android.os.INetworkManagementService;
|
||||
import android.provider.Settings;
|
||||
import android.support.test.filters.SmallTest;
|
||||
@@ -31,11 +46,17 @@ import com.android.internal.util.test.FakeSettingsProvider;
|
||||
import com.android.internal.R;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Tests for IpManager.
|
||||
*/
|
||||
@@ -44,14 +65,20 @@ import org.mockito.MockitoAnnotations;
|
||||
public class IpManagerTest {
|
||||
private static final int DEFAULT_AVOIDBADWIFI_CONFIG_VALUE = 1;
|
||||
|
||||
private static final String VALID = "VALID";
|
||||
private static final String INVALID = "INVALID";
|
||||
|
||||
@Mock private Context mContext;
|
||||
@Mock private INetworkManagementService mNMService;
|
||||
@Mock private Resources mResources;
|
||||
@Mock private Callback mCb;
|
||||
@Mock private AlarmManager mAlarm;
|
||||
private MockContentResolver mContentResolver;
|
||||
|
||||
@Before public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
|
||||
when(mContext.getResources()).thenReturn(mResources);
|
||||
when(mResources.getInteger(R.integer.config_networkAvoidBadWifi))
|
||||
.thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE);
|
||||
@@ -68,7 +95,152 @@ public class IpManagerTest {
|
||||
|
||||
@Test
|
||||
public void testInvalidInterfaceDoesNotThrow() throws Exception {
|
||||
final IpManager.Callback cb = new IpManager.Callback();
|
||||
final IpManager ipm = new IpManager(mContext, "test_wlan0", cb, mNMService);
|
||||
final IpManager ipm = new IpManager(mContext, "test_wlan0", mCb, mNMService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultProvisioningConfiguration() throws Exception {
|
||||
final String iface = "test_wlan0";
|
||||
final IpManager ipm = new IpManager(mContext, iface, mCb, mNMService);
|
||||
ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
|
||||
.withoutIPv4()
|
||||
// TODO: mock IpReachabilityMonitor's dependencies (NetworkInterface, PowerManager)
|
||||
// and enable it in this test
|
||||
.withoutIpReachabilityMonitor()
|
||||
.build();
|
||||
|
||||
ipm.startProvisioning(config);
|
||||
verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
|
||||
verify(mCb, timeout(100).times(1)).setFallbackMulticastFilter(false);
|
||||
verify(mCb, never()).onProvisioningFailure(any());
|
||||
|
||||
ipm.stop();
|
||||
verify(mNMService, timeout(100).times(1)).disableIpv6(iface);
|
||||
verify(mNMService, timeout(100).times(1)).clearInterfaceAddresses(iface);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitialConfigurations() throws Exception {
|
||||
InitialConfigurationTestCase[] testcases = {
|
||||
validConf("valid IPv4 configuration",
|
||||
links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("192.0.2.2")),
|
||||
validConf("another valid IPv4 configuration",
|
||||
links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns()),
|
||||
validConf("valid IPv6 configurations",
|
||||
links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
|
||||
prefixes("2001:db8:dead:beef::/64", "fe80::/64"),
|
||||
dns("2001:db8:dead:beef:f00::02")),
|
||||
validConf("valid IPv6 configurations",
|
||||
links("fe80::1/64"), prefixes("fe80::/64"), dns()),
|
||||
validConf("valid IPv6/v4 configuration",
|
||||
links("2001:db8:dead:beef:f00::a0/48", "192.0.2.12/24"),
|
||||
prefixes("2001:db8:dead:beef::/64", "192.0.2.0/24"),
|
||||
dns("192.0.2.2", "2001:db8:dead:beef:f00::02")),
|
||||
validConf("valid IPv6 configuration without any GUA.",
|
||||
links("fd00:1234:5678::1/48"),
|
||||
prefixes("fd00:1234:5678::/48"),
|
||||
dns("fd00:1234:5678::1000")),
|
||||
|
||||
invalidConf("v4 addr and dns not in any prefix",
|
||||
links("192.0.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
|
||||
invalidConf("v4 addr not in any prefix",
|
||||
links("198.51.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
|
||||
invalidConf("v4 dns addr not in any prefix",
|
||||
links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("198.51.100.2")),
|
||||
invalidConf("v6 addr not in any prefix",
|
||||
links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
|
||||
prefixes("2001:db8:dead:beef::/64"),
|
||||
dns("2001:db8:dead:beef:f00::02")),
|
||||
invalidConf("v6 dns addr not in any prefix",
|
||||
links("fe80::1/64"), prefixes("fe80::/64"), dns("2001:db8:dead:beef:f00::02")),
|
||||
invalidConf("default ipv6 route and no GUA",
|
||||
links("fd01:1111:2222:3333::a0/128"), prefixes("::/0"), dns()),
|
||||
invalidConf("invalid v6 prefix length",
|
||||
links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/32"),
|
||||
dns()),
|
||||
invalidConf("another invalid v6 prefix length",
|
||||
links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/72"),
|
||||
dns())
|
||||
};
|
||||
|
||||
for (InitialConfigurationTestCase testcase : testcases) {
|
||||
if (testcase.config.isValid() != testcase.isValid) {
|
||||
fail(testcase.errorMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class InitialConfigurationTestCase {
|
||||
String descr;
|
||||
boolean isValid;
|
||||
InitialConfiguration config;
|
||||
public String errorMessage() {
|
||||
return String.format("%s: expected configuration %s to be %s, but was %s",
|
||||
descr, config, validString(isValid), validString(!isValid));
|
||||
}
|
||||
}
|
||||
|
||||
static String validString(boolean isValid) {
|
||||
return isValid ? VALID : INVALID;
|
||||
}
|
||||
|
||||
static InitialConfigurationTestCase validConf(String descr, Set<LinkAddress> links,
|
||||
Set<IpPrefix> prefixes, Set<InetAddress> dns) {
|
||||
return confTestCase(descr, true, conf(links, prefixes, dns));
|
||||
}
|
||||
|
||||
static InitialConfigurationTestCase invalidConf(String descr, Set<LinkAddress> links,
|
||||
Set<IpPrefix> prefixes, Set<InetAddress> dns) {
|
||||
return confTestCase(descr, false, conf(links, prefixes, dns));
|
||||
}
|
||||
|
||||
static InitialConfigurationTestCase confTestCase(
|
||||
String descr, boolean isValid, InitialConfiguration config) {
|
||||
InitialConfigurationTestCase testcase = new InitialConfigurationTestCase();
|
||||
testcase.descr = descr;
|
||||
testcase.isValid = isValid;
|
||||
testcase.config = config;
|
||||
return testcase;
|
||||
}
|
||||
|
||||
static InitialConfiguration conf(
|
||||
Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns) {
|
||||
InitialConfiguration conf = new InitialConfiguration();
|
||||
conf.ipAddresses.addAll(links);
|
||||
conf.directlyConnectedRoutes.addAll(prefixes);
|
||||
conf.dnsServers.addAll(dns);
|
||||
return conf;
|
||||
}
|
||||
|
||||
static Set<IpPrefix> prefixes(String... prefixes) {
|
||||
return mapIntoSet(prefixes, IpPrefix::new);
|
||||
}
|
||||
|
||||
static Set<LinkAddress> links(String... addresses) {
|
||||
return mapIntoSet(addresses, LinkAddress::new);
|
||||
}
|
||||
|
||||
static Set<InetAddress> ips(String... addresses) {
|
||||
return mapIntoSet(addresses, InetAddress::getByName);
|
||||
}
|
||||
|
||||
static Set<InetAddress> dns(String... addresses) {
|
||||
return ips(addresses);
|
||||
}
|
||||
|
||||
static <A, B> Set<B> mapIntoSet(A[] in, Fn<A, B> fn) {
|
||||
Set<B> out = new HashSet<>(in.length);
|
||||
for (A item : in) {
|
||||
try {
|
||||
out.add(fn.call(item));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
interface Fn<A,B> {
|
||||
B call(A a) throws Exception;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user