aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/apps/segmentrouting/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/apps/segmentrouting/src/main')
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java5
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java24
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java164
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java4
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java104
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java190
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java66
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java9
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java81
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java9
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java18
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java10
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java78
13 files changed, 612 insertions, 150 deletions
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
index f42f84b1..36563f01 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
@@ -35,7 +35,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
-import java.util.List;
+import java.util.Set;
+
import static com.google.common.base.Preconditions.checkNotNull;
public class ArpHandler {
@@ -112,7 +113,7 @@ public class ArpHandler {
private boolean isArpReqForRouter(DeviceId deviceId, ARP arpRequest) {
- List<Ip4Address> gatewayIpAddresses = config.getSubnetGatewayIps(deviceId);
+ Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId);
if (gatewayIpAddresses != null) {
Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpRequest
.getTargetProtocolAddress());
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
index 40ee55fc..c4a91c75 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
@@ -23,14 +23,12 @@ import org.onlab.packet.IpPrefix;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
-import org.onosproject.net.MastershipRole;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -97,7 +95,7 @@ public class DefaultRoutingHandler {
log.debug("populateAllRoutingRules: populationStatus is STARTED");
for (Device sw : srManager.deviceService.getDevices()) {
- if (srManager.mastershipService.getLocalRole(sw.id()) != MastershipRole.MASTER) {
+ if (!srManager.mastershipService.isLocalMaster(sw.id())) {
log.debug("populateAllRoutingRules: skipping device {}...we are not master",
sw.id());
continue;
@@ -146,8 +144,7 @@ public class DefaultRoutingHandler {
// Take the snapshots of the links
updatedEcmpSpgMap = new HashMap<>();
for (Device sw : srManager.deviceService.getDevices()) {
- if (srManager.mastershipService.
- getLocalRole(sw.id()) != MastershipRole.MASTER) {
+ if (!srManager.mastershipService.isLocalMaster(sw.id())) {
continue;
}
ECMPShortestPathGraph ecmpSpgUpdated =
@@ -273,8 +270,7 @@ public class DefaultRoutingHandler {
for (Device sw : srManager.deviceService.getDevices()) {
log.debug("Computing the impacted routes for device {} due to link fail",
sw.id());
- if (srManager.mastershipService.
- getLocalRole(sw.id()) != MastershipRole.MASTER) {
+ if (!srManager.mastershipService.isLocalMaster(sw.id())) {
continue;
}
ECMPShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
@@ -320,8 +316,7 @@ public class DefaultRoutingHandler {
for (Device sw : srManager.deviceService.getDevices()) {
log.debug("Computing the impacted routes for device {}",
sw.id());
- if (srManager.mastershipService.
- getLocalRole(sw.id()) != MastershipRole.MASTER) {
+ if (!srManager.mastershipService.isLocalMaster(sw.id())) {
log.debug("No mastership for {} and skip route optimization",
sw.id());
continue;
@@ -455,7 +450,7 @@ public class DefaultRoutingHandler {
// If both target switch and dest switch are edge routers, then set IP
// rule for both subnet and router IP.
if (config.isEdgeDevice(targetSw) && config.isEdgeDevice(destSw)) {
- List<Ip4Prefix> subnets = config.getSubnets(destSw);
+ Set<Ip4Prefix> subnets = config.getSubnets(destSw);
log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for subnets {}",
targetSw, destSw, subnets);
result = rulePopulator.populateIpRuleForSubnet(targetSw,
@@ -499,14 +494,13 @@ public class DefaultRoutingHandler {
}
/**
- * Populates table miss entries for all tables, and pipeline rules for VLAN
- * and TCAM tables. XXX rename/rethink
+ * Populates filtering rules for permitting Router DstMac and VLAN.
*
* @param deviceId Switch ID to set the rules
*/
- public void populateTtpRules(DeviceId deviceId) {
- rulePopulator.populateTableVlan(deviceId);
- rulePopulator.populateTableTMac(deviceId);
+ public void populatePortAddressingRules(DeviceId deviceId) {
+ rulePopulator.populateRouterMacVlanFilters(deviceId);
+ rulePopulator.populateRouterIpPunts(deviceId);
}
/**
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
index 0bc155b8..828c51ce 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.segmentrouting;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
@@ -38,20 +39,20 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Segment Routing configuration component that reads the
* segment routing related configuration from Network Configuration Manager
* component and organizes in more accessible formats.
- *
- * TODO: Merge multiple Segment Routing configuration wrapper classes into one.
*/
public class DeviceConfiguration implements DeviceProperties {
private static final Logger log = LoggerFactory
.getLogger(DeviceConfiguration.class);
private final List<Integer> allSegmentIds = new ArrayList<>();
- private final HashMap<DeviceId, SegmentRouterInfo> deviceConfigMap = new HashMap<>();
+ private final ConcurrentHashMap<DeviceId, SegmentRouterInfo> deviceConfigMap
+ = new ConcurrentHashMap<>();
private class SegmentRouterInfo {
int nodeSid;
@@ -126,18 +127,17 @@ public class DeviceConfiguration implements DeviceProperties {
}
/**
- * Returns the segment id of a segment router.
+ * Returns the Node segment id of a segment router.
*
* @param deviceId device identifier
* @return segment id
*/
@Override
public int getSegmentId(DeviceId deviceId) {
- if (deviceConfigMap.get(deviceId) != null) {
- log.trace("getSegmentId for device{} is {}",
- deviceId,
- deviceConfigMap.get(deviceId).nodeSid);
- return deviceConfigMap.get(deviceId).nodeSid;
+ SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+ if (srinfo != null) {
+ log.trace("getSegmentId for device{} is {}", deviceId, srinfo.nodeSid);
+ return srinfo.nodeSid;
} else {
log.warn("getSegmentId for device {} "
+ "throwing IllegalStateException "
@@ -147,10 +147,10 @@ public class DeviceConfiguration implements DeviceProperties {
}
/**
- * Returns the segment id of a segment router given its mac address.
+ * Returns the Node segment id of a segment router given its Router mac address.
*
* @param routerMac router mac address
- * @return segment id
+ * @return node segment id, or -1 if not found in config
*/
public int getSegmentId(MacAddress routerMac) {
for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
@@ -164,10 +164,10 @@ public class DeviceConfiguration implements DeviceProperties {
}
/**
- * Returns the segment id of a segment router given its router ip address.
+ * Returns the Node segment id of a segment router given its Router ip address.
*
* @param routerAddress router ip address
- * @return segment id
+ * @return node segment id, or -1 if not found in config
*/
public int getSegmentId(Ip4Address routerAddress) {
for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
@@ -188,11 +188,10 @@ public class DeviceConfiguration implements DeviceProperties {
*/
@Override
public MacAddress getDeviceMac(DeviceId deviceId) {
- if (deviceConfigMap.get(deviceId) != null) {
- log.trace("getDeviceMac for device{} is {}",
- deviceId,
- deviceConfigMap.get(deviceId).mac);
- return deviceConfigMap.get(deviceId).mac;
+ SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+ if (srinfo != null) {
+ log.trace("getDeviceMac for device{} is {}", deviceId, srinfo.mac);
+ return srinfo.mac;
} else {
log.warn("getDeviceMac for device {} "
+ "throwing IllegalStateException "
@@ -208,11 +207,10 @@ public class DeviceConfiguration implements DeviceProperties {
* @return router ip address
*/
public Ip4Address getRouterIp(DeviceId deviceId) {
- if (deviceConfigMap.get(deviceId) != null) {
- log.trace("getDeviceIp for device{} is {}",
- deviceId,
- deviceConfigMap.get(deviceId).ip);
- return deviceConfigMap.get(deviceId).ip;
+ SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+ if (srinfo != null) {
+ log.trace("getDeviceIp for device{} is {}", deviceId, srinfo.ip);
+ return srinfo.ip;
} else {
log.warn("getRouterIp for device {} "
+ "throwing IllegalStateException "
@@ -223,18 +221,17 @@ public class DeviceConfiguration implements DeviceProperties {
/**
* Indicates if the segment router is a edge router or
- * a transit/back bone router.
+ * a core/backbone router.
*
* @param deviceId device identifier
* @return boolean
*/
@Override
public boolean isEdgeDevice(DeviceId deviceId) {
- if (deviceConfigMap.get(deviceId) != null) {
- log.trace("isEdgeDevice for device{} is {}",
- deviceId,
- deviceConfigMap.get(deviceId).isEdge);
- return deviceConfigMap.get(deviceId).isEdge;
+ SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+ if (srinfo != null) {
+ log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge);
+ return srinfo.isEdge;
} else {
log.warn("isEdgeDevice for device {} "
+ "throwing IllegalStateException "
@@ -244,15 +241,35 @@ public class DeviceConfiguration implements DeviceProperties {
}
/**
- * Returns the segment ids of all configured segment routers.
+ * Returns the node segment ids of all configured segment routers.
*
- * @return list of segment ids
+ * @return list of node segment ids
*/
@Override
public List<Integer> getAllDeviceSegmentIds() {
return allSegmentIds;
}
+ @Override
+ public Map<Ip4Prefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId) {
+ Map<Ip4Prefix, List<PortNumber>> subnetPortMap = new HashMap<>();
+
+ // Construct subnet-port mapping from port-subnet mapping
+ Map<PortNumber, Ip4Prefix> portSubnetMap =
+ this.deviceConfigMap.get(deviceId).subnets;
+ portSubnetMap.forEach((port, subnet) -> {
+ if (subnetPortMap.containsKey(subnet)) {
+ subnetPortMap.get(subnet).add(port);
+ } else {
+ ArrayList<PortNumber> ports = new ArrayList<>();
+ ports.add(port);
+ subnetPortMap.put(subnet, ports);
+ }
+ });
+
+ return subnetPortMap;
+ }
+
/**
* Returns the device identifier or data plane identifier (dpid)
* of a segment router given its segment id.
@@ -290,37 +307,68 @@ public class DeviceConfiguration implements DeviceProperties {
}
/**
- * Returns the configured subnet gateway ip addresses for a segment router.
+ * Returns the configured port ip addresses for a segment router.
+ * These addresses serve as gateway IP addresses for the subnets configured
+ * on those ports.
*
* @param deviceId device identifier
- * @return list of ip addresses
+ * @return immutable set of ip addresses configured on the ports or null if not found
*/
- public List<Ip4Address> getSubnetGatewayIps(DeviceId deviceId) {
- if (deviceConfigMap.get(deviceId) != null) {
- log.trace("getSubnetGatewayIps for device{} is {}",
- deviceId,
- deviceConfigMap.get(deviceId).gatewayIps.values());
- return new ArrayList<>(deviceConfigMap.get(deviceId).gatewayIps.values());
- } else {
- return null;
+ public Set<Ip4Address> getPortIPs(DeviceId deviceId) {
+ SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+ if (srinfo != null) {
+ log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
+ srinfo.gatewayIps.values());
+ return ImmutableSet.copyOf(srinfo.gatewayIps.values());
+ }
+ return null;
+ }
+
+ /**
+ * 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
- * @return list of ip prefixes
+ * @return list of ip prefixes or null if not found
*/
- public List<Ip4Prefix> getSubnets(DeviceId deviceId) {
- if (deviceConfigMap.get(deviceId) != null) {
- log.trace("getSubnets for device{} is {}",
- deviceId,
- deviceConfigMap.get(deviceId).subnets.values());
- return new ArrayList<>(deviceConfigMap.get(deviceId).subnets.values());
- } else {
- return null;
+ public Set<Ip4Prefix> getSubnets(DeviceId deviceId) {
+ SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+ if (srinfo != null) {
+ log.trace("getSubnets for device{} is {}", deviceId,
+ srinfo.subnets.values());
+ return ImmutableSet.copyOf(srinfo.subnets.values());
}
+ return null;
+ }
+
+ /**
+ * Returns the configured subnet on the given port, or null if no
+ * subnet has been configured on the port.
+ *
+ * @param deviceId device identifier
+ * @param pnum port identifier
+ * @return configured subnet on port, or null
+ */
+ public Ip4Prefix getPortSubnet(DeviceId deviceId, PortNumber pnum) {
+ SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+ if (srinfo != null) {
+ return srinfo.subnets.get(pnum);
+ }
+ return null;
}
/**
@@ -349,7 +397,7 @@ public class DeviceConfiguration implements DeviceProperties {
* specified ip address as one of its subnet gateway ip address.
*
* @param gatewayIpAddress router gateway ip address
- * @return router mac address
+ * @return router mac address or null if not found
*/
public MacAddress getRouterMacForAGatewayIp(Ip4Address gatewayIpAddress) {
for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
@@ -377,7 +425,7 @@ public class DeviceConfiguration implements DeviceProperties {
*/
public boolean inSameSubnet(DeviceId deviceId, Ip4Address hostIp) {
- List<Ip4Prefix> subnets = getSubnets(deviceId);
+ Set<Ip4Prefix> subnets = getSubnets(deviceId);
if (subnets == null) {
return false;
}
@@ -399,8 +447,9 @@ public class DeviceConfiguration implements DeviceProperties {
* @return list of port numbers
*/
public List<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
- if (deviceConfigMap.get(deviceId) != null) {
- for (AdjacencySid asid : deviceConfigMap.get(deviceId).adjacencySids) {
+ SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+ if (srinfo != null) {
+ for (AdjacencySid asid : srinfo.adjacencySids) {
if (asid.getAsid() == sid) {
return asid.getPorts();
}
@@ -419,12 +468,13 @@ public class DeviceConfiguration implements DeviceProperties {
* otherwise false
*/
public boolean isAdjacencySid(DeviceId deviceId, int sid) {
- if (deviceConfigMap.get(deviceId) != null) {
- if (deviceConfigMap.get(deviceId).adjacencySids.isEmpty()) {
+ SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+ if (srinfo != null) {
+ if (srinfo.adjacencySids.isEmpty()) {
return false;
} else {
for (AdjacencySid asid:
- deviceConfigMap.get(deviceId).adjacencySids) {
+ srinfo.adjacencySids) {
if (asid.getAsid() == sid) {
return true;
}
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
index f65f03e0..b3916b06 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
@@ -32,7 +32,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
-import java.util.List;
+import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -70,7 +70,7 @@ public class IcmpHandler {
DeviceId deviceId = connectPoint.deviceId();
Ip4Address destinationAddress =
Ip4Address.valueOf(ipv4.getDestinationAddress());
- List<Ip4Address> gatewayIpAddresses = config.getSubnetGatewayIps(deviceId);
+ Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId);
Ip4Address routerIp = config.getRouterIp(deviceId);
IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
Ip4Address routerIpAddress = routerIpPrefix.getIp4Prefix().address();
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index 7641571d..d46028e7 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -25,6 +25,7 @@ import org.onlab.packet.VlanId;
import org.onosproject.segmentrouting.grouphandler.NeighborSet;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
+import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -38,11 +39,13 @@ import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.flowobjective.ForwardingObjective.Builder;
+import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
import org.onosproject.net.flowobjective.ObjectiveContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
@@ -57,6 +60,11 @@ public class RoutingRulePopulator {
private AtomicLong rulePopulationCounter;
private SegmentRoutingManager srManager;
private DeviceConfiguration config;
+
+ private static final int HIGHEST_PRIORITY = 0xffff;
+ private static final long OFPP_MAX = 0xffffff00L;
+
+
/**
* Creates a RoutingRulePopulator object.
*
@@ -98,7 +106,7 @@ public class RoutingRulePopulator {
TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
- sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, 32));
+ sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, IpPrefix.MAX_INET_MASK_LENGTH));
sbuilder.matchEthType(Ethernet.TYPE_IPV4);
tbuilder.deferred()
@@ -134,7 +142,7 @@ public class RoutingRulePopulator {
* @return true if all rules are set successfully, false otherwise
*/
public boolean populateIpRuleForSubnet(DeviceId deviceId,
- List<Ip4Prefix> subnets,
+ Set<Ip4Prefix> subnets,
DeviceId destSw,
Set<DeviceId> nextHops) {
@@ -350,40 +358,80 @@ public class RoutingRulePopulator {
}
/**
- * Populates VLAN flows rules. All packets are forwarded to TMAC table.
+ * Creates a filtering objective to permit all untagged packets with a
+ * dstMac corresponding to the router's MAC address. For those pipelines
+ * that need to internally assign vlans to untagged packets, this method
+ * provides per-subnet vlan-ids as metadata.
+ * <p>
+ * Note that the vlan assignment is only done by the master-instance for a switch.
+ * However we send the filtering objective from slave-instances as well, so
+ * that drivers can obtain other information (like Router MAC and IP).
*
- * @param deviceId switch ID to set the rules
+ * @param deviceId the switch dpid for the router
*/
- public void populateTableVlan(DeviceId deviceId) {
- FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
- fob.withKey(Criteria.matchInPort(PortNumber.ALL))
+ public void populateRouterMacVlanFilters(DeviceId deviceId) {
+ log.debug("Installing per-port filtering objective for untagged "
+ + "packets in device {}", deviceId);
+ for (Port port : srManager.deviceService.getPorts(deviceId)) {
+ if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
+ Ip4Prefix portSubnet = config.getPortSubnet(deviceId, port.number());
+ VlanId assignedVlan = (portSubnet == null)
+ ? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET)
+ : srManager.getSubnetAssignedVlanId(deviceId, portSubnet);
+ FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
+ fob.withKey(Criteria.matchInPort(port.number()))
+ .addCondition(Criteria.matchEthDst(config.getDeviceMac(deviceId)))
.addCondition(Criteria.matchVlanId(VlanId.NONE));
- fob.permit().fromApp(srManager.appId);
- log.debug("populateTableVlan: Installing filtering objective for untagged packets");
- srManager.flowObjectiveService.
- filter(deviceId,
- fob.add(new SRObjectiveContext(deviceId,
- SRObjectiveContext.ObjectiveType.FILTER)));
+ // vlan assignment is valid only if this instance is master
+ if (srManager.mastershipService.isLocalMaster(deviceId)) {
+ TrafficTreatment tt = DefaultTrafficTreatment.builder()
+ .pushVlan().setVlanId(assignedVlan).build();
+ fob.setMeta(tt);
+ }
+ fob.permit().fromApp(srManager.appId);
+ srManager.flowObjectiveService.
+ filter(deviceId, fob.add(new SRObjectiveContext(deviceId,
+ SRObjectiveContext.ObjectiveType.FILTER)));
+ }
+ }
}
/**
- * Populates TMAC table rules. IP packets are forwarded to IP table. MPLS
- * packets are forwarded to MPLS table.
+ * Creates a forwarding objective to punt all IP packets, destined to the
+ * router's port IP addresses, to the controller. Note that the input
+ * port should not be matched on, as these packets can come from any input.
+ * Furthermore, these are applied only by the master instance.
*
- * @param deviceId switch ID to set the rules
+ * @param deviceId the switch dpid for the router
*/
- public void populateTableTMac(DeviceId deviceId) {
-
- FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
- fob.withKey(Criteria.matchInPort(PortNumber.ALL))
- .addCondition(Criteria.matchEthDst(config
- .getDeviceMac(deviceId)));
- fob.permit().fromApp(srManager.appId);
- log.debug("populateTableTMac: Installing filtering objective for router mac");
- srManager.flowObjectiveService.
- filter(deviceId,
- fob.add(new SRObjectiveContext(deviceId,
- SRObjectiveContext.ObjectiveType.FILTER)));
+ public void populateRouterIpPunts(DeviceId deviceId) {
+ if (!srManager.mastershipService.isLocalMaster(deviceId)) {
+ log.debug("Not installing port-IP punts - not the master for dev:{} ",
+ deviceId);
+ return;
+ }
+ ForwardingObjective.Builder puntIp = DefaultForwardingObjective.builder();
+ Set<Ip4Address> allIps = new HashSet<Ip4Address>(config.getPortIPs(deviceId));
+ allIps.add(config.getRouterIp(deviceId));
+ for (Ip4Address ipaddr : allIps) {
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ selector.matchEthType(Ethernet.TYPE_IPV4);
+ selector.matchIPDst(IpPrefix.valueOf(ipaddr,
+ IpPrefix.MAX_INET_MASK_LENGTH));
+ treatment.setOutput(PortNumber.CONTROLLER);
+ puntIp.withSelector(selector.build());
+ puntIp.withTreatment(treatment.build());
+ puntIp.withFlag(Flag.VERSATILE)
+ .withPriority(HIGHEST_PRIORITY)
+ .makePermanent()
+ .fromApp(srManager.appId);
+ log.debug("Installing forwarding objective to punt port IP addresses");
+ srManager.flowObjectiveService.
+ forward(deviceId,
+ puntIp.add(new SRObjectiveContext(deviceId,
+ SRObjectiveContext.ObjectiveType.FORWARDING)));
+ }
}
private PortNumber selectOnePort(DeviceId srcId, Set<DeviceId> destIds) {
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index eb2cf569..9d60b279 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -22,11 +22,17 @@ import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.Ethernet;
+import org.onlab.packet.VlanId;
import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
import org.onlab.util.KryoNamespace;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.event.Event;
+import org.onosproject.net.ConnectPoint;
import org.onosproject.net.config.ConfigFactory;
import org.onosproject.net.config.NetworkConfigEvent;
import org.onosproject.net.config.NetworkConfigRegistry;
@@ -45,7 +51,6 @@ import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.group.GroupKey;
import org.onosproject.net.host.HostService;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.link.LinkEvent;
@@ -56,6 +61,7 @@ import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.onosproject.net.topology.TopologyService;
+import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.store.service.EventuallyConsistentMapBuilder;
import org.onosproject.store.service.StorageService;
@@ -64,9 +70,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
@@ -133,8 +141,13 @@ public class SegmentRoutingManager implements SegmentRoutingService {
// Per device next objective ID store with (device id + neighbor set) as key
private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
Integer> nsNextObjStore = null;
+ private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
private EventuallyConsistentMap<String, Policy> policyStore = null;
+ // Per device, per-subnet assigned-vlans store, with (device id + subnet
+ // IPv4 prefix) as key
+ private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
+ subnetVidStore = null;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
@@ -163,6 +176,9 @@ public class SegmentRoutingManager implements SegmentRoutingService {
private KryoNamespace.Builder kryoBuilder = null;
+ private static final short ASSIGNED_VLAN_START = 4093;
+ public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
+
@Activate
protected void activate() {
appId = coreService
@@ -170,6 +186,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
kryoBuilder = new KryoNamespace.Builder()
.register(NeighborSetNextObjectiveStoreKey.class,
+ SubnetNextObjectiveStoreKey.class,
+ SubnetAssignedVidStoreKey.class,
NeighborSet.class,
DeviceId.class,
URI.class,
@@ -180,7 +198,12 @@ public class SegmentRoutingManager implements SegmentRoutingService {
DefaultTunnel.class,
Policy.class,
TunnelPolicy.class,
- Policy.Type.class
+ Policy.Type.class,
+ VlanId.class,
+ Ip4Address.class,
+ Ip4Prefix.class,
+ IpAddress.Version.class,
+ ConnectPoint.class
);
log.debug("Creating EC map nsnextobjectivestore");
@@ -194,6 +217,16 @@ public class SegmentRoutingManager implements SegmentRoutingService {
.build();
log.trace("Current size {}", nsNextObjStore.size());
+ log.debug("Creating EC map subnetnextobjectivestore");
+ EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
+ subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
+
+ subnetNextObjStore = subnetNextObjMapBuilder
+ .withName("subnetnextobjectivestore")
+ .withSerializer(kryoBuilder)
+ .withTimestampProvider((k, v) -> new WallClockTimestamp())
+ .build();
+
EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
storageService.eventuallyConsistentMapBuilder();
@@ -212,6 +245,15 @@ public class SegmentRoutingManager implements SegmentRoutingService {
.withTimestampProvider((k, v) -> new WallClockTimestamp())
.build();
+ EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
+ subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
+
+ subnetVidStore = subnetVidStoreMapBuilder
+ .withName("subnetvidstore")
+ .withSerializer(kryoBuilder)
+ .withTimestampProvider((k, v) -> new WallClockTimestamp())
+ .build();
+
cfgService.addListener(cfgListener);
cfgService.registerConfigFactory(cfgFactory);
@@ -296,23 +338,72 @@ public class SegmentRoutingManager implements SegmentRoutingService {
}
/**
- * Returns the GroupKey object for the device and the NeighborSet given.
- * XXX is this called
+ * Returns the vlan-id assigned to the subnet configured for a device.
+ * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
+ * if and only if this controller instance is the master for the device.
+ * <p>
+ * USAGE: The assigned vlans are meant to be applied to untagged packets on those
+ * switches/pipelines that need this functionality. These vids are meant
+ * to be used internally within a switch, and thus need to be unique only
+ * on a switch level. Note that packets never go out on the wire with these
+ * vlans. Currently, vlan ids are assigned from value 4093 down.
+ * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
+ * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
+ * per subnet.
+ * XXX This method should avoid any vlans configured on the ports, but
+ * currently the app works only on untagged packets and as a result
+ * ignores any vlan configuration.
*
- * @param ns NeightborSet object for the GroupKey
- * @return GroupKey object for the NeighborSet
+ * @param deviceId switch dpid
+ * @param subnet IPv4 prefix for which assigned vlan is desired
+ * @return VlanId assigned for the subnet on the device, or
+ * null if no vlan assignment was found and this instance is not
+ * the master for the device.
*/
- public GroupKey getGroupKey(NeighborSet ns) {
- for (DefaultGroupHandler groupHandler : groupHandlerMap.values()) {
- return groupHandler.getGroupKey(ns);
+ public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
+ VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
+ deviceId, subnet));
+ if (assignedVid != null) {
+ log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
+ + "{}", subnet, deviceId, assignedVid);
+ return assignedVid;
+ }
+ //check mastership for the right to assign a vlan
+ if (!mastershipService.isLocalMaster(deviceId)) {
+ log.warn("This controller instance is not the master for device {}. "
+ + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
+ return null;
+ }
+ // vlan assignment is expensive but done only once
+ Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
+ Set<Short> assignedVlans = new HashSet<>();
+ Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
+ for (Ip4Prefix sub : configuredSubnets) {
+ VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
+ sub));
+ if (v != null) {
+ assignedVlans.add(v.toShort());
+ } else {
+ unassignedSubnets.add(sub);
+ }
+ }
+ short nextAssignedVlan = ASSIGNED_VLAN_START;
+ if (!assignedVlans.isEmpty()) {
+ nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
+ }
+ for (Ip4Prefix unsub : unassignedSubnets) {
+ subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
+ VlanId.vlanId(nextAssignedVlan--));
+ log.info("Assigned vlan: {} to subnet: {} on device: {}",
+ nextAssignedVlan + 1, unsub, deviceId);
}
- return null;
+ return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
}
/**
- * Returns the next objective ID for the NeighborSet given. If the nextObjectiveID does not exist,
- * a new one is created and returned.
+ * Returns the next objective ID for the given NeighborSet.
+ * If the nextObjectiveID does not exist, a new one is created and returned.
*
* @param deviceId Device ID
* @param ns NegighborSet
@@ -329,6 +420,25 @@ public class SegmentRoutingManager implements SegmentRoutingService {
}
}
+ /**
+ * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist,
+ * a new one is created and returned.
+ *
+ * @param deviceId Device ID
+ * @param prefix Subnet
+ * @return next objective ID
+ */
+ public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
+ if (groupHandlerMap.get(deviceId) != null) {
+ log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
+ return groupHandlerMap
+ .get(deviceId).getSubnetNextObjectiveId(prefix);
+ } else {
+ log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId);
+ return -1;
+ }
+ }
+
private class InternalPacketProcessor implements PacketProcessor {
@Override
public void process(PacketContext context) {
@@ -423,6 +533,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
if (deviceService.isAvailable(((Device) event.subject()).id())) {
+ log.info("Processing device event {} for available device {}",
+ event.type(), ((Device) event.subject()).id());
processDeviceAdded((Device) event.subject());
}
} else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
@@ -484,20 +596,31 @@ public class SegmentRoutingManager implements SegmentRoutingService {
private void processDeviceAdded(Device device) {
log.debug("A new device with ID {} was added", device.id());
- //Irrespective whether the local is a MASTER or not for this device,
- //create group handler instance and push default TTP flow rules.
- //Because in a multi-instance setup, instances can initiate
- //groups for any devices. Also the default TTP rules are needed
- //to be pushed before inserting any IP table entries for any device
- DefaultGroupHandler dgh = DefaultGroupHandler.
+ // Irrespective of whether the local is a MASTER or not for this device,
+ // we need to create a SR-group-handler instance. This is because in a
+ // multi-instance setup, any instance can initiate forwarding/next-objectives
+ // for any switch (even if this instance is a SLAVE or not even connected
+ // to the switch). To handle this, a default-group-handler instance is necessary
+ // per switch.
+ DefaultGroupHandler groupHandler = DefaultGroupHandler.
createGroupHandler(device.id(),
appId,
deviceConfiguration,
linkService,
flowObjectiveService,
- nsNextObjStore);
- groupHandlerMap.put(device.id(), dgh);
- defaultRoutingHandler.populateTtpRules(device.id());
+ nsNextObjStore,
+ subnetNextObjStore);
+ groupHandlerMap.put(device.id(), groupHandler);
+
+ // Also, in some cases, drivers may need extra
+ // information to process rules (eg. Router IP/MAC); and so, we send
+ // port addressing rules to the driver as well irrespective of whether
+ // this instance is the master or not.
+ defaultRoutingHandler.populatePortAddressingRules(device.id());
+
+ if (mastershipService.isLocalMaster(device.id())) {
+ groupHandler.createGroupsFromSubnetConfig();
+ }
}
private void processPortRemoved(Device device, Port port) {
@@ -531,18 +654,29 @@ public class SegmentRoutingManager implements SegmentRoutingService {
tunnelHandler, policyStore);
for (Device device : deviceService.getDevices()) {
- //Irrespective whether the local is a MASTER or not for this device,
- //create group handler instance and push default TTP flow rules.
- //Because in a multi-instance setup, instances can initiate
- //groups for any devices. Also the default TTP rules are needed
- //to be pushed before inserting any IP table entries for any device
+ // Irrespective of whether the local is a MASTER or not for this device,
+ // we need to create a SR-group-handler instance. This is because in a
+ // multi-instance setup, any instance can initiate forwarding/next-objectives
+ // for any switch (even if this instance is a SLAVE or not even connected
+ // to the switch). To handle this, a default-group-handler instance is necessary
+ // per switch.
DefaultGroupHandler groupHandler = DefaultGroupHandler
.createGroupHandler(device.id(), appId,
deviceConfiguration, linkService,
flowObjectiveService,
- nsNextObjStore);
+ nsNextObjStore,
+ subnetNextObjStore);
groupHandlerMap.put(device.id(), groupHandler);
- defaultRoutingHandler.populateTtpRules(device.id());
+
+ // Also, in some cases, drivers may need extra
+ // information to process rules (eg. Router IP/MAC); and so, we send
+ // port addressing rules to the driver as well, irrespective of whether
+ // this instance is the master or not.
+ defaultRoutingHandler.populatePortAddressingRules(device.id());
+
+ if (mastershipService.isLocalMaster(device.id())) {
+ groupHandler.createGroupsFromSubnetConfig();
+ }
}
defaultRoutingHandler.startPopulationProcess();
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java
new file mode 100644
index 00000000..84b44c97
--- /dev/null
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java
@@ -0,0 +1,66 @@
+package org.onosproject.segmentrouting;
+
+import java.util.Objects;
+
+import org.onlab.packet.Ip4Prefix;
+import org.onosproject.net.DeviceId;
+
+/**
+ * Class definition for key used to map per device subnets to assigned Vlan ids.
+ *
+ */
+public class SubnetAssignedVidStoreKey {
+ private final DeviceId deviceId;
+ private final Ip4Prefix subnet;
+
+ public SubnetAssignedVidStoreKey(DeviceId deviceId, Ip4Prefix subnet) {
+ this.deviceId = deviceId;
+ this.subnet = subnet;
+ }
+
+ /**
+ * Returns the device identification used to create this key.
+ *
+ * @return the device identifier
+ */
+ public DeviceId deviceId() {
+ return deviceId;
+ }
+
+ /**
+ * Returns the subnet information used to create this key.
+ *
+ * @return the subnet
+ */
+ public Ip4Prefix subnet() {
+ return subnet;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof SubnetAssignedVidStoreKey)) {
+ return false;
+ }
+ SubnetAssignedVidStoreKey that =
+ (SubnetAssignedVidStoreKey) o;
+ return (Objects.equals(this.deviceId, that.deviceId) &&
+ Objects.equals(this.subnet, that.subnet));
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + Objects.hashCode(deviceId)
+ + Objects.hashCode(subnet);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "Device: " + deviceId + " Subnet: " + subnet;
+ }
+
+}
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java
index c960adca..a5c1090f 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java
@@ -52,9 +52,12 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler {
LinkService linkService,
FlowObjectiveService flowObjService,
EventuallyConsistentMap<
- NeighborSetNextObjectiveStoreKey,
- Integer> nsNextObjStore) {
- super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
+ NeighborSetNextObjectiveStoreKey,
+ Integer> nsNextObjStore,
+ EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+ Integer> subnetNextObjStore) {
+ super(deviceId, appId, config, linkService, flowObjService,
+ nsNextObjStore, subnetNextObjStore);
}
@Override
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
index 9bbde2f3..69a0d86f 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
@@ -25,10 +25,11 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.util.KryoNamespace;
@@ -74,7 +75,8 @@ public class DefaultGroupHandler {
// new HashMap<NeighborSet, Integer>();
protected EventuallyConsistentMap<
NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore = null;
- protected Random rand = new Random();
+ protected EventuallyConsistentMap<
+ SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
.register(URI.class).register(HashSet.class)
@@ -89,8 +91,10 @@ public class DefaultGroupHandler {
LinkService linkService,
FlowObjectiveService flowObjService,
EventuallyConsistentMap<
- NeighborSetNextObjectiveStoreKey,
- Integer> nsNextObjStore) {
+ NeighborSetNextObjectiveStoreKey,
+ Integer> nsNextObjStore,
+ EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+ Integer> subnetNextObjStore) {
this.deviceId = checkNotNull(deviceId);
this.appId = checkNotNull(appId);
this.deviceConfig = checkNotNull(config);
@@ -101,6 +105,7 @@ public class DefaultGroupHandler {
nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
this.flowObjectiveService = flowObjService;
this.nsNextObjStore = nsNextObjStore;
+ this.subnetNextObjStore = subnetNextObjStore;
populateNeighborMaps();
}
@@ -115,7 +120,8 @@ public class DefaultGroupHandler {
* @param config interface to retrieve the device properties
* @param linkService link service object
* @param flowObjService flow objective service object
- * @param nsNextObjStore next objective store map
+ * @param nsNextObjStore NeighborSet next objective store map
+ * @param subnetNextObjStore subnet next objective store map
* @return default group handler type
*/
public static DefaultGroupHandler createGroupHandler(DeviceId deviceId,
@@ -123,18 +129,23 @@ public class DefaultGroupHandler {
DeviceProperties config,
LinkService linkService,
FlowObjectiveService flowObjService,
- EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
- Integer> nsNextObjStore) {
+ EventuallyConsistentMap<
+ NeighborSetNextObjectiveStoreKey,
+ Integer> nsNextObjStore,
+ EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+ Integer> subnetNextObjStore) {
if (config.isEdgeDevice(deviceId)) {
return new DefaultEdgeGroupHandler(deviceId, appId, config,
linkService,
flowObjService,
- nsNextObjStore);
+ nsNextObjStore,
+ subnetNextObjStore);
} else {
return new DefaultTransitGroupHandler(deviceId, appId, config,
linkService,
flowObjService,
- nsNextObjStore);
+ nsNextObjStore,
+ subnetNextObjStore);
}
}
@@ -323,6 +334,21 @@ public class DefaultGroupHandler {
}
/**
+ * Returns the next objective associated with the subnet.
+ * If there is no next objective for this subnet, this API
+ * would create a next objective and return.
+ *
+ * @param prefix subnet information
+ * @return int if found or -1
+ */
+ public int getSubnetNextObjectiveId(IpPrefix prefix) {
+ Integer nextId = subnetNextObjStore.
+ get(new SubnetNextObjectiveStoreKey(deviceId, prefix));
+
+ return (nextId != null) ? nextId : -1;
+ }
+
+ /**
* Checks if the next objective ID (group) for the neighbor set exists or not.
*
* @param ns neighbor set to check
@@ -486,6 +512,43 @@ public class DefaultGroupHandler {
}
}
+ public void createGroupsFromSubnetConfig() {
+ Map<Ip4Prefix, List<PortNumber>> subnetPortMap =
+ this.deviceConfig.getSubnetPortsMap(this.deviceId);
+
+ // Construct a broadcast group for each subnet
+ subnetPortMap.forEach((subnet, ports) -> {
+ SubnetNextObjectiveStoreKey key =
+ new SubnetNextObjectiveStoreKey(deviceId, subnet);
+
+ if (subnetNextObjStore.containsKey(key)) {
+ log.debug("Broadcast group for device {} and subnet {} exists",
+ deviceId, subnet);
+ return;
+ }
+
+ int nextId = flowObjectiveService.allocateNextId();
+
+ NextObjective.Builder nextObjBuilder = DefaultNextObjective
+ .builder().withId(nextId)
+ .withType(NextObjective.Type.BROADCAST).fromApp(appId);
+
+ ports.forEach(port -> {
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ tBuilder.setOutput(port);
+ nextObjBuilder.addTreatment(tBuilder.build());
+ });
+
+ NextObjective nextObj = nextObjBuilder.add();
+ flowObjectiveService.next(deviceId, nextObj);
+ log.debug("createGroupFromSubnetConfig: Submited "
+ + "next objective {} in device {}",
+ nextId, deviceId);
+
+ subnetNextObjStore.put(key, nextId);
+ });
+ }
+
public GroupKey getGroupKey(Object obj) {
return new DefaultGroupKey(kryo.build().serialize(obj));
}
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java
index 3cb73aba..b009e869 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java
@@ -45,9 +45,12 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler {
LinkService linkService,
FlowObjectiveService flowObjService,
EventuallyConsistentMap<
- NeighborSetNextObjectiveStoreKey,
- Integer> nsNextObjStore) {
- super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
+ NeighborSetNextObjectiveStoreKey,
+ Integer> nsNextObjStore,
+ EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+ Integer> subnetNextObjStore) {
+ super(deviceId, appId, config, linkService, flowObjService,
+ nsNextObjStore, subnetNextObjStore);
}
@Override
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java
index 497f5256..d28d38d5 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java
@@ -16,9 +16,12 @@
package org.onosproject.segmentrouting.grouphandler;
import java.util.List;
+import java.util.Map;
+import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.MacAddress;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
/**
* Mechanism through which group handler module retrieves
@@ -33,6 +36,7 @@ public interface DeviceProperties {
* @return segment id of a device
*/
int getSegmentId(DeviceId deviceId);
+
/**
* Returns the Mac address of a device to be used in group creation.
*
@@ -40,6 +44,7 @@ public interface DeviceProperties {
* @return mac address of a device
*/
MacAddress getDeviceMac(DeviceId deviceId);
+
/**
* Indicates whether a device is edge device or transit/core device.
*
@@ -47,6 +52,7 @@ public interface DeviceProperties {
* @return boolean
*/
boolean isEdgeDevice(DeviceId deviceId);
+
/**
* Returns all segment IDs to be considered in building auto
*
@@ -54,4 +60,16 @@ public interface DeviceProperties {
* @return list of segment IDs
*/
List<Integer> getAllDeviceSegmentIds();
+
+ /**
+ * Returns subnet-to-ports mapping of given device.
+ *
+ * For each entry of the map
+ * Key: a subnet
+ * Value: a list of ports, which are bound to the subnet
+ *
+ * @param deviceId device identifier
+ * @return a map that contains all subnet-to-ports mapping of given device
+ */
+ Map<Ip4Prefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId);
}
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java
index e7e87839..e47a6625 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java
@@ -54,7 +54,8 @@ public class PolicyGroupHandler extends DefaultGroupHandler {
* @param config interface to retrieve the device properties
* @param linkService link service object
* @param flowObjService flow objective service object
- * @param nsNextObjStore next objective store map
+ * @param nsNextObjStore NeighborSet next objective store map
+ * @param subnetNextObjStore subnet next objective store map
*/
public PolicyGroupHandler(DeviceId deviceId,
ApplicationId appId,
@@ -62,8 +63,11 @@ public class PolicyGroupHandler extends DefaultGroupHandler {
LinkService linkService,
FlowObjectiveService flowObjService,
EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
- Integer> nsNextObjStore) {
- super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
+ Integer> nsNextObjStore,
+ EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+ Integer> subnetNextObjStore) {
+ super(deviceId, appId, config, linkService, flowObjService,
+ nsNextObjStore, subnetNextObjStore);
}
public PolicyGroupIdentifier createPolicyGroupChain(String id,
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java
new file mode 100644
index 00000000..d6b16c7a
--- /dev/null
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014-2015 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.grouphandler;
+
+import org.onlab.packet.IpPrefix;
+import org.onosproject.net.DeviceId;
+
+import java.util.Objects;
+
+/**
+ * Class definition of Key for Subnet to NextObjective store.
+ */
+public class SubnetNextObjectiveStoreKey {
+ private final DeviceId deviceId;
+ private final IpPrefix prefix;
+
+ public SubnetNextObjectiveStoreKey(DeviceId deviceId,
+ IpPrefix prefix) {
+ this.deviceId = deviceId;
+ this.prefix = prefix;
+ }
+
+ /**
+ * Gets device id in this SubnetNextObjectiveStoreKey.
+ *
+ * @return device id
+ */
+ public DeviceId deviceId() {
+ return this.deviceId;
+ }
+
+ /**
+ * Gets subnet information in this SubnetNextObjectiveStoreKey.
+ *
+ * @return subnet information
+ */
+ public IpPrefix prefix() {
+ return this.prefix;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof SubnetNextObjectiveStoreKey)) {
+ return false;
+ }
+ SubnetNextObjectiveStoreKey that =
+ (SubnetNextObjectiveStoreKey) o;
+ return (Objects.equals(this.deviceId, that.deviceId) &&
+ Objects.equals(this.prefix, that.prefix));
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(deviceId, prefix);
+ }
+
+ @Override
+ public String toString() {
+ return "Device: " + deviceId + " Subnet: " + prefix;
+ }
+}