[CORD-458] Updates ARP handler
Changes:
- SR application uses NRM;
- Adds hooks for ND protocol;
- Updates ARP handler to better leverage on NRM;
- Reworks to take into account IPv4/IPv6 together;
Change-Id: Iab55b8c5ef7d973928d8ad47e2c2a482fb9c5c8a
diff --git a/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java b/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
index 255f740..94f95f4 100644
--- a/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
+++ b/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
@@ -21,6 +21,7 @@
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.Ip6Address;
+import org.onlab.packet.Ip6Prefix;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
@@ -37,6 +38,7 @@
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -57,6 +59,7 @@
private static final String ERROR_CONFIG = "Configuration error.";
private static final String TOO_MANY_SUBNET = ERROR_CONFIG + " Too many subnets configured on {}";
private static final String NO_SUBNET = "No subnet configured on {}";
+ private static final String MISCONFIGURED = "Subnets are not configured correctly for {}";
private static final Logger log = LoggerFactory.getLogger(DeviceConfiguration.class);
private final List<Integer> allSegmentIds = new ArrayList<>();
@@ -71,12 +74,12 @@
Ip6Address ipv6Loopback;
MacAddress mac;
boolean isEdge;
- Map<PortNumber, Ip4Address> gatewayIps;
- SetMultimap<PortNumber, Ip4Prefix> subnets;
+ SetMultimap<PortNumber, IpAddress> gatewayIps;
+ SetMultimap<PortNumber, IpPrefix> subnets;
Map<Integer, Set<Integer>> adjacencySids;
public SegmentRouterInfo() {
- gatewayIps = new HashMap<>();
+ gatewayIps = HashMultimap.create();
subnets = HashMultimap.create();
}
}
@@ -116,6 +119,7 @@
// Read gatewayIps and subnets from port subject. Ignore suppressed ports.
Set<ConnectPoint> portSubjects = srManager.cfgService
.getSubjects(ConnectPoint.class, InterfaceConfig.class);
+
portSubjects.stream().filter(subject -> !isSuppressedPort(subject)).forEach(subject -> {
InterfaceConfig config =
srManager.cfgService.getConfig(subject, InterfaceConfig.class);
@@ -138,15 +142,27 @@
// Extract subnet information
List<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddressesList();
interfaceAddresses.forEach(interfaceAddress -> {
- // Do not add /0 and /32 to gateway IP list
+ // Do not add /0, /32 and /128 to gateway IP list
int prefixLength = interfaceAddress.subnetAddress().prefixLength();
- if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
- info.gatewayIps.put(port, interfaceAddress.ipAddress().getIp4Address());
+ IpPrefix ipPrefix = interfaceAddress.subnetAddress();
+ if (ipPrefix.isIp4()) {
+ if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
+ info.gatewayIps.put(port, interfaceAddress.ipAddress());
+ }
+ info.subnets.put(port, interfaceAddress.subnetAddress());
+ } else {
+ if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET6_MASK_LENGTH) {
+ info.gatewayIps.put(port, interfaceAddress.ipAddress());
+ }
+ info.subnets.put(port, interfaceAddress.subnetAddress());
}
- info.subnets.put(port, interfaceAddress.subnetAddress().getIp4Prefix());
});
}
});
+ /*
+ * We register the connect point with the NRS.
+ */
+ srManager.registerConnectPoint(subject);
});
}
@@ -301,7 +317,7 @@
}
@Override
- public Map<Ip4Prefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
+ public Map<IpPrefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
throws DeviceConfigNotFoundException {
SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
if (srinfo == null) {
@@ -309,14 +325,15 @@
throw new DeviceConfigNotFoundException(message);
}
// Construct subnet-port mapping from port-subnet mapping
- SetMultimap<PortNumber, Ip4Prefix> portSubnetMap = srinfo.subnets;
- Map<Ip4Prefix, List<PortNumber>> subnetPortMap = new HashMap<>();
+ SetMultimap<PortNumber, IpPrefix> portSubnetMap = srinfo.subnets;
+ Map<IpPrefix, List<PortNumber>> subnetPortMap = new HashMap<>();
portSubnetMap.entries().forEach(entry -> {
PortNumber port = entry.getKey();
- Ip4Prefix subnet = entry.getValue();
+ IpPrefix subnet = entry.getValue();
- if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH) {
+ if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
+ subnet.prefixLength() == IpPrefix.MAX_INET6_MASK_LENGTH) {
return;
}
@@ -394,7 +411,7 @@
* @param deviceId device identifier
* @return immutable set of ip addresses configured on the ports or null if not found
*/
- public Set<Ip4Address> getPortIPs(DeviceId deviceId) {
+ public Set<IpAddress> getPortIPs(DeviceId deviceId) {
SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
if (srinfo != null) {
log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
@@ -410,10 +427,10 @@
* @param deviceId device identifier
* @return list of ip prefixes or null if not found
*/
- public Set<Ip4Prefix> getSubnets(DeviceId deviceId) {
+ public Set<IpPrefix> getSubnets(DeviceId deviceId) {
SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
if (srinfo != null) {
- ImmutableSet.Builder<Ip4Prefix> builder = ImmutableSet.builder();
+ ImmutableSet.Builder<IpPrefix> builder = ImmutableSet.builder();
return builder.addAll(srinfo.subnets.values()).build();
}
return null;
@@ -425,17 +442,17 @@
*
* @param deviceId Device ID
* @param port Port number
- * @return The subnet configured on given port or null if
+ * @return The subnets configured on given port or empty set if
* the port is unconfigured, misconfigured or suppressed.
*/
- public Ip4Prefix getPortSubnet(DeviceId deviceId, PortNumber port) {
+ public Set<IpPrefix> getPortSubnets(DeviceId deviceId, PortNumber port) {
ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
if (isSuppressedPort(connectPoint)) {
- return null;
+ return Collections.emptySet();
}
- Set<Ip4Prefix> subnets =
+ Set<IpPrefix> subnets =
srManager.interfaceService.getInterfacesByPort(connectPoint).stream()
.flatMap(intf -> intf.ipAddressesList().stream())
.map(InterfaceIpAddress::subnetAddress)
@@ -444,13 +461,69 @@
if (subnets.isEmpty()) {
log.info(NO_SUBNET, connectPoint);
- return null;
- } else if (subnets.size() > 1) {
+ return Collections.emptySet();
+ } else if (subnets.size() > 2) {
log.warn(TOO_MANY_SUBNET, connectPoint);
- return null;
- } else {
- return subnets.stream().findFirst().orElse(null);
+ return Collections.emptySet();
+ } else if (verifySubnets(subnets)) {
+ return subnets;
}
+ log.warn(MISCONFIGURED, connectPoint);
+ return Collections.emptySet();
+ }
+
+ /**
+ * Returns the IPv4 subnet configured of given device and port.
+ *
+ * @param deviceId Device ID
+ * @param port Port number
+ * @return The IPv4 subnet configured on given port or null if
+ * the port is unconfigured, misconfigured or suppressed.
+ */
+ public Ip4Prefix getPortIPv4Subnet(DeviceId deviceId, PortNumber port) {
+ return getPortSubnets(deviceId, port).stream()
+ .filter(IpPrefix::isIp4)
+ .map(IpPrefix::getIp4Prefix)
+ .findFirst().orElse(null);
+ }
+
+ /**
+ * Returns the IPv6 subnet configured of given device and port.
+ *
+ * @param deviceId Device ID
+ * @param port Port number
+ * @return The IPV6 subnet configured on given port or null if
+ * the port is unconfigured, misconfigured or suppressed.
+ */
+ public Ip6Prefix getPortIPv6Subnet(DeviceId deviceId, PortNumber port) {
+ return getPortSubnets(deviceId, port).stream()
+ .filter(IpPrefix::isIp6)
+ .map(IpPrefix::getIp6Prefix)
+ .findFirst().orElse(null);
+ }
+
+ /**
+ * Utility to verify the configuration of a given port.
+ *
+ * @param subnets the subnets set to verify
+ * @return true if the configured subnets are ok. False otherwise.
+ */
+ private boolean verifySubnets(Set<IpPrefix> subnets) {
+ Set<Ip4Prefix> ip4Prefices = subnets.stream()
+ .filter(IpPrefix::isIp4)
+ .map(IpPrefix::getIp4Prefix)
+ .collect(Collectors.toSet());
+ if (ip4Prefices.size() > 1) {
+ return false;
+ }
+ Set<Ip6Prefix> ip6Prefices = subnets.stream()
+ .filter(IpPrefix::isIp6)
+ .map(IpPrefix::getIp6Prefix)
+ .collect(Collectors.toSet());
+ if (ip6Prefices.size() > 1) {
+ return false;
+ }
+ return !(ip4Prefices.isEmpty() && ip6Prefices.isEmpty());
}
/**
@@ -510,7 +583,7 @@
* @param gatewayIpAddress router gateway ip address
* @return router mac address or null if not found
*/
- public MacAddress getRouterMacForAGatewayIp(Ip4Address gatewayIpAddress) {
+ public MacAddress getRouterMacForAGatewayIp(IpAddress gatewayIpAddress) {
for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
deviceConfigMap.entrySet()) {
if (entry.getValue().gatewayIps.
@@ -534,14 +607,14 @@
* false if no subnet is defined under the router or if the host is not
* within the subnet defined in the router
*/
- public boolean inSameSubnet(DeviceId deviceId, Ip4Address hostIp) {
+ public boolean inSameSubnet(DeviceId deviceId, IpAddress hostIp) {
- Set<Ip4Prefix> subnets = getSubnets(deviceId);
+ Set<IpPrefix> subnets = getSubnets(deviceId);
if (subnets == null) {
return false;
}
- for (Ip4Prefix subnet: subnets) {
+ for (IpPrefix subnet: subnets) {
// Exclude /0 since it is a special case used for default route
if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
return true;
@@ -561,8 +634,10 @@
* there is no subnet configuration on given connect point.
*/
public boolean inSameSubnet(ConnectPoint connectPoint, IpAddress ip) {
- Ip4Prefix portSubnet = getPortSubnet(connectPoint.deviceId(), connectPoint.port());
- return portSubnet != null && portSubnet.contains(ip);
+ Ip4Prefix ipv4Subnet = getPortIPv4Subnet(connectPoint.deviceId(), connectPoint.port());
+ Ip6Prefix ipv6Subnet = getPortIPv6Subnet(connectPoint.deviceId(), connectPoint.port());
+ return (ipv4Subnet != null && ipv4Subnet.contains(ip)) ||
+ (ipv6Subnet != null && ipv6Subnet.contains(ip));
}
/**
@@ -596,34 +671,34 @@
* Add subnet to specific connect point.
*
* @param cp connect point
- * @param ip4Prefix subnet being added to the device
+ * @param ipPrefix subnet being added to the device
*/
- public void addSubnet(ConnectPoint cp, Ip4Prefix ip4Prefix) {
+ public void addSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
checkNotNull(cp);
- checkNotNull(ip4Prefix);
+ checkNotNull(ipPrefix);
SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
if (srinfo == null) {
log.warn("Device {} is not configured. Abort.", cp.deviceId());
return;
}
- srinfo.subnets.put(cp.port(), ip4Prefix);
+ srinfo.subnets.put(cp.port(), ipPrefix);
}
/**
* Remove subnet from specific connect point.
*
* @param cp connect point
- * @param ip4Prefix subnet being removed to the device
+ * @param ipPrefix subnet being removed to the device
*/
- public void removeSubnet(ConnectPoint cp, Ip4Prefix ip4Prefix) {
+ public void removeSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
checkNotNull(cp);
- checkNotNull(ip4Prefix);
+ checkNotNull(ipPrefix);
SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
if (srinfo == null) {
log.warn("Device {} is not configured. Abort.", cp.deviceId());
return;
}
- srinfo.subnets.remove(cp.port(), ip4Prefix);
+ srinfo.subnets.remove(cp.port(), ipPrefix);
}
private boolean isSuppressedPort(ConnectPoint connectPoint) {