CORD-512 Support vSG <-> vRouter default route
- Support multiple subnets per port. getIpPort() will only return the first non-/32 and non-/0 subnet
/32 is used as vSG subnet
/0 is used as default gateway
- Support multiple L3 unicast group on a single port
Change the way to generate the group ID and group key
- Special case for 0.0.0.0 host. Push a /0 to IP table instead of /32
- Implement vRouterConfig
Put VR MAC to TMAC table of all leaves when config added
When processEthDst see PortNumber.ANY in key, match ETH_DST only
- For OFDPA, wipe existing instruction before sending to controller
So packet that misses L3 unicast table won't be sent to controller twice
- For SpringOpenTTP, pop VLAN before sending to controller
- Move several constant definitions to SegmentRoutingService
- Add minimum priority for IP rules such that /0 won't collide with zero priority default rules
- Update the config sample
Use VLAN=-1 for hosts
Add example for default route
Change-Id: Id751697ce36a7e5c13b3859350ff21b585c38525
diff --git a/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java b/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
index 3d2d337..db4bc63 100644
--- a/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
+++ b/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
@@ -15,9 +15,12 @@
*/
package org.onosproject.segmentrouting.config;
+import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.incubator.net.config.basics.ConfigException;
@@ -37,6 +40,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -59,13 +63,13 @@
Ip4Address ip;
MacAddress mac;
boolean isEdge;
- HashMap<PortNumber, Ip4Address> gatewayIps;
- HashMap<PortNumber, Ip4Prefix> subnets;
+ Map<PortNumber, Ip4Address> gatewayIps;
+ SetMultimap<PortNumber, Ip4Prefix> subnets;
Map<Integer, Set<Integer>> adjacencySids;
public SegmentRouterInfo() {
gatewayIps = new HashMap<>();
- subnets = new HashMap<>();
+ subnets = HashMultimap.create();
}
}
@@ -78,10 +82,10 @@
public DeviceConfiguration(NetworkConfigRegistry cfgService) {
// Read config from device subject, excluding gatewayIps and subnets.
Set<DeviceId> deviceSubjects =
- cfgService.getSubjects(DeviceId.class, SegmentRoutingConfig.class);
+ cfgService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class);
deviceSubjects.forEach(subject -> {
- SegmentRoutingConfig config =
- cfgService.getConfig(subject, SegmentRoutingConfig.class);
+ SegmentRoutingDeviceConfig config =
+ cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
SegmentRouterInfo info = new SegmentRouterInfo();
info.deviceId = subject;
info.nodeSid = config.nodeSid();
@@ -119,7 +123,11 @@
// Extract subnet information
Set<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddresses();
interfaceAddresses.forEach(interfaceAddress -> {
- info.gatewayIps.put(port, interfaceAddress.ipAddress().getIp4Address());
+ // Do not add /0 and /32 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());
+ }
info.subnets.put(port, interfaceAddress.subnetAddress().getIp4Prefix());
});
@@ -247,9 +255,13 @@
Map<Ip4Prefix, List<PortNumber>> subnetPortMap = new HashMap<>();
// Construct subnet-port mapping from port-subnet mapping
- Map<PortNumber, Ip4Prefix> portSubnetMap =
+ SetMultimap<PortNumber, Ip4Prefix> portSubnetMap =
this.deviceConfigMap.get(deviceId).subnets;
- portSubnetMap.forEach((port, subnet) -> {
+
+ portSubnetMap.entries().forEach(entry -> {
+ PortNumber port = entry.getKey();
+ Ip4Prefix subnet = entry.getValue();
+
if (subnetPortMap.containsKey(subnet)) {
subnetPortMap.get(subnet).add(port);
} else {
@@ -258,7 +270,6 @@
subnetPortMap.put(subnet, ports);
}
});
-
return subnetPortMap;
}
@@ -322,21 +333,6 @@
}
/**
- * Returns the configured IP addresses per port
- * for a segment router.
- *
- * @param deviceId device identifier
- * @return map of port to gateway IP addresses or null if not found
- */
- public Map<PortNumber, Ip4Address> getPortIPMap(DeviceId deviceId) {
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- if (srinfo != null) {
- return srinfo.gatewayIps;
- }
- return null;
- }
-
- /**
* Returns the configured subnet prefixes for a segment router.
*
* @param deviceId device identifier
@@ -353,8 +349,8 @@
}
/**
- * Returns the configured subnet on the given port, or null if no
- * subnet has been configured on the port.
+ * Returns the configured non-/32 and non-/0 subnet on the given port,
+ * or null if no subnet has been configured on the port.
*
* @param deviceId device identifier
* @param pnum port identifier
@@ -363,7 +359,12 @@
public Ip4Prefix getPortSubnet(DeviceId deviceId, PortNumber pnum) {
SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
if (srinfo != null) {
- return srinfo.subnets.get(pnum);
+ Optional<Ip4Prefix> result = srinfo.subnets.get(pnum).stream()
+ .filter(subnet ->
+ subnet.getIp4Prefix().prefixLength() != IpPrefix.MAX_INET_MASK_LENGTH &&
+ subnet.getIp4Prefix().prefixLength() != 0)
+ .findFirst();
+ return (result.isPresent()) ? result.get() : null;
}
return null;
}
@@ -378,7 +379,7 @@
public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
deviceConfigMap.entrySet()) {
- for (Ip4Prefix prefix:entry.getValue().subnets.values()) {
+ for (Ip4Prefix prefix : entry.getValue().subnets.values()) {
if (prefix.contains(destIpAddress)) {
return entry.getValue().ip;
}
@@ -428,7 +429,8 @@
}
for (Ip4Prefix subnet: subnets) {
- if (subnet.contains(hostIp)) {
+ // Exclude /0 since it is a special case used for default route
+ if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
return true;
}
}
diff --git a/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingAppConfig.java b/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingAppConfig.java
new file mode 100644
index 0000000..e39fb18
--- /dev/null
+++ b/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingAppConfig.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.segmentrouting.config;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.google.common.collect.ImmutableSet;
+import org.onlab.packet.MacAddress;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.config.Config;
+import java.util.Set;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * App configuration object for Segment Routing.
+ */
+public class SegmentRoutingAppConfig extends Config<ApplicationId> {
+ private static final String VROUTER_MACS = "vRouterMacs";
+
+ @Override
+ public boolean isValid() {
+ return hasOnlyFields(VROUTER_MACS) && vRouterMacs() != null;
+ }
+
+ /**
+ * Gets vRouters from the config.
+ *
+ * @return a set of vRouter MAC addresses
+ */
+ public Set<MacAddress> vRouterMacs() {
+ if (!object.has(VROUTER_MACS)) {
+ return null;
+ }
+
+ ImmutableSet.Builder<MacAddress> builder = ImmutableSet.builder();
+ ArrayNode arrayNode = (ArrayNode) object.path(VROUTER_MACS);
+ for (JsonNode jsonNode : arrayNode) {
+ MacAddress mac;
+
+ String macStr = jsonNode.asText(null);
+ if (macStr == null) {
+ return null;
+ }
+ try {
+ mac = MacAddress.valueOf(macStr);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+
+ builder.add(mac);
+ }
+ return builder.build();
+ }
+
+ /**
+ * Sets vRouters to the config.
+ *
+ * @param vRouterMacs a set of vRouter MAC addresses
+ * @return this {@link SegmentRoutingAppConfig}
+ */
+ public SegmentRoutingAppConfig setVRouterMacs(Set<MacAddress> vRouterMacs) {
+ if (vRouterMacs == null) {
+ object.remove(VROUTER_MACS);
+ } else {
+ ArrayNode arrayNode = mapper.createArrayNode();
+
+ vRouterMacs.forEach(mac -> {
+ arrayNode.add(mac.toString());
+ });
+
+ object.set(VROUTER_MACS, arrayNode);
+ }
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("vRouterMacs", vRouterMacs())
+ .toString();
+ }
+}
diff --git a/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java b/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingDeviceConfig.java
similarity index 87%
rename from src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java
rename to src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingDeviceConfig.java
index 64486c6..10c69ca 100644
--- a/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java
+++ b/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingDeviceConfig.java
@@ -34,7 +34,7 @@
/**
* Configuration object for Segment Routing Application.
*/
-public class SegmentRoutingConfig extends Config<DeviceId> {
+public class SegmentRoutingDeviceConfig extends Config<DeviceId> {
private static final String NAME = "name";
private static final String IP = "routerIp";
private static final String MAC = "routerMac";
@@ -71,8 +71,8 @@
* @param name name of the router.
* @return the config of the router.
*/
- public SegmentRoutingConfig setName(String name) {
- return (SegmentRoutingConfig) setOrClear(NAME, name);
+ public SegmentRoutingDeviceConfig setName(String name) {
+ return (SegmentRoutingDeviceConfig) setOrClear(NAME, name);
}
/**
@@ -91,8 +91,8 @@
* @param ip IP address of the router.
* @return the config of the router.
*/
- public SegmentRoutingConfig setRouterIp(String ip) {
- return (SegmentRoutingConfig) setOrClear(IP, ip);
+ public SegmentRoutingDeviceConfig setRouterIp(String ip) {
+ return (SegmentRoutingDeviceConfig) setOrClear(IP, ip);
}
/**
@@ -111,8 +111,8 @@
* @param mac MAC address of the router.
* @return the config of the router.
*/
- public SegmentRoutingConfig setRouterMac(String mac) {
- return (SegmentRoutingConfig) setOrClear(MAC, mac);
+ public SegmentRoutingDeviceConfig setRouterMac(String mac) {
+ return (SegmentRoutingDeviceConfig) setOrClear(MAC, mac);
}
/**
@@ -130,8 +130,8 @@
* @param sid node SID of the router.
* @return the config of the router.
*/
- public SegmentRoutingConfig setNodeSid(int sid) {
- return (SegmentRoutingConfig) setOrClear(SID, sid);
+ public SegmentRoutingDeviceConfig setNodeSid(int sid) {
+ return (SegmentRoutingDeviceConfig) setOrClear(SID, sid);
}
/**
@@ -154,8 +154,8 @@
* @param isEdgeRouter true if the router is an edge router.
* @return the config of the router.
*/
- public SegmentRoutingConfig setIsEdgeRouter(boolean isEdgeRouter) {
- return (SegmentRoutingConfig) setOrClear(EDGE, isEdgeRouter);
+ public SegmentRoutingDeviceConfig setIsEdgeRouter(boolean isEdgeRouter) {
+ return (SegmentRoutingDeviceConfig) setOrClear(EDGE, isEdgeRouter);
}
/**
@@ -197,7 +197,7 @@
* @param adjacencySids adjacency SIDs of the router.
* @return the config of the router.
*/
- public SegmentRoutingConfig setAdjacencySids(Map<Integer, Set<Integer>> adjacencySids) {
+ public SegmentRoutingDeviceConfig setAdjacencySids(Map<Integer, Set<Integer>> adjacencySids) {
if (adjacencySids == null) {
object.remove(ADJSIDS);
} else {