Srikanth Vavilapalli

ONOS-1823 and ONOS-1838:Segment Routing Multi-instance Support-1

Change-Id: I3cc848415a609a9c4001d135e51104c62fb2830d
Showing 18 changed files with 381 additions and 230 deletions
......@@ -89,14 +89,18 @@ public class DefaultRoutingHandler {
populationStatus = Status.STARTED;
rulePopulator.resetCounter();
log.info("Starts to populate routing rules");
log.debug("populateAllRoutingRules: populationStatus is STARTED");
for (Device sw : srManager.deviceService.getDevices()) {
if (srManager.mastershipService.getLocalRole(sw.id()) != MastershipRole.MASTER) {
log.debug("populateAllRoutingRules: skipping device {}...we are not master",
sw.id());
continue;
}
ECMPShortestPathGraph ecmpSpg = new ECMPShortestPathGraph(sw.id(), srManager);
if (!populateEcmpRoutingRules(sw.id(), ecmpSpg)) {
log.debug("populateAllRoutingRules: populationStatus is ABORTED");
populationStatus = Status.ABORTED;
log.debug("Abort routing rule population");
return false;
......@@ -106,6 +110,7 @@ public class DefaultRoutingHandler {
// TODO: Set adjacency routing rule for all switches
}
log.debug("populateAllRoutingRules: populationStatus is SUCCEEDED");
populationStatus = Status.SUCCEEDED;
log.info("Completes routing rule population. Total # of rules pushed : {}",
rulePopulator.getCounter());
......@@ -144,6 +149,8 @@ public class DefaultRoutingHandler {
log.info("Starts rule population from link change");
Set<ArrayList<DeviceId>> routeChanges;
log.trace("populateRoutingRulesForLinkStatusChange: "
+ "populationStatus is STARTED");
populationStatus = Status.STARTED;
if (linkFail == null) {
// Compare all routes of existing ECMP SPG with the new ones
......@@ -155,16 +162,19 @@ public class DefaultRoutingHandler {
if (routeChanges.isEmpty()) {
log.info("No route changes for the link status change");
log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
populationStatus = Status.SUCCEEDED;
return true;
}
if (repopulateRoutingRulesForRoutes(routeChanges)) {
log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
populationStatus = Status.SUCCEEDED;
log.info("Complete to repopulate the rules. # of rules populated : {}",
rulePopulator.getCounter());
return true;
} else {
log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is ABORTED");
populationStatus = Status.ABORTED;
log.warn("Failed to repopulate the rules.");
return false;
......@@ -177,6 +187,7 @@ public class DefaultRoutingHandler {
for (ArrayList<DeviceId> link: routes) {
// When only the source device is defined, reinstall routes to all other devices
if (link.size() == 1) {
log.trace("repopulateRoutingRulesForRoutes: running ECMP graph for device {}", link.get(0));
ECMPShortestPathGraph ecmpSpg = new ECMPShortestPathGraph(link.get(0), srManager);
if (populateEcmpRoutingRules(link.get(0), ecmpSpg)) {
currentEcmpSpgMap.put(link.get(0), ecmpSpg);
......@@ -187,8 +198,7 @@ public class DefaultRoutingHandler {
} else {
DeviceId src = link.get(0);
DeviceId dst = link.get(1);
log.trace("repopulateRoutingRulesForRoutes: running ECMP graph "
+ "for device {}", dst);
log.trace("repopulateRoutingRulesForRoutes: running ECMP graph for device {}", dst);
ECMPShortestPathGraph ecmpSpg = updatedEcmpSpgMap.get(dst);
HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
ecmpSpg.getAllLearnedSwitchesAndVia();
......@@ -278,14 +288,12 @@ public class DefaultRoutingHandler {
log.debug("Checking route change for switch {}", sw.id());
ECMPShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
if (ecmpSpg == null) {
log.debug("No existing ECMP path for Switch {}", sw.id());
log.debug("No existing ECMP graph for device {}", sw.id());
ArrayList<DeviceId> route = new ArrayList<>();
route.add(sw.id());
routes.add(route);
continue;
}
log.debug("computeRouteChange: running ECMP graph "
+ "for device {}", sw.id());
ECMPShortestPathGraph newEcmpSpg = updatedEcmpSpgMap.get(sw.id());
currentEcmpSpgMap.put(sw.id(), newEcmpSpg);
HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
......@@ -400,6 +408,8 @@ public class DefaultRoutingHandler {
// rule for both subnet and router IP.
if (config.isEdgeDevice(targetSw) && config.isEdgeDevice(destSw)) {
List<Ip4Prefix> subnets = config.getSubnets(destSw);
log.debug("populateEcmpRoutingRulePartial in device {} towards {} for subnets {}",
targetSw, destSw, subnets);
result = rulePopulator.populateIpRuleForSubnet(targetSw,
subnets,
destSw,
......@@ -410,6 +420,8 @@ public class DefaultRoutingHandler {
Ip4Address routerIp = config.getRouterIp(destSw);
IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
log.debug("populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
targetSw, destSw, routerIpPrefix);
result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
if (!result) {
return false;
......@@ -419,6 +431,8 @@ public class DefaultRoutingHandler {
} else if (config.isEdgeDevice(targetSw)) {
Ip4Address routerIp = config.getRouterIp(destSw);
IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
log.debug("populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
targetSw, destSw, routerIpPrefix);
result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
if (!result) {
return false;
......@@ -426,6 +440,8 @@ public class DefaultRoutingHandler {
}
// Populates MPLS rules to all routers
log.debug("populateEcmpRoutingRulePartial in device{} towards {} for all MPLS rules",
targetSw, destSw);
result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops);
if (!result) {
return false;
......@@ -453,9 +469,13 @@ public class DefaultRoutingHandler {
public void startPopulationProcess() {
synchronized (populationStatus) {
if (populationStatus == Status.IDLE
|| populationStatus == Status.SUCCEEDED) {
|| populationStatus == Status.SUCCEEDED
|| populationStatus == Status.ABORTED) {
populationStatus = Status.STARTED;
populateAllRoutingRules();
} else {
log.warn("Not initiating startPopulationProcess as populationStatus is {}",
populationStatus);
}
}
}
......
......@@ -99,6 +99,9 @@ public class DeviceConfiguration implements DeviceProperties {
deviceConfigMap.get(deviceId).nodeSid);
return deviceConfigMap.get(deviceId).nodeSid;
} else {
log.warn("getSegmentId for device {} "
+ "throwing IllegalStateException "
+ "because device does not exist in config", deviceId);
throw new IllegalStateException();
}
}
......@@ -151,6 +154,9 @@ public class DeviceConfiguration implements DeviceProperties {
deviceConfigMap.get(deviceId).mac);
return deviceConfigMap.get(deviceId).mac;
} else {
log.warn("getDeviceMac for device {} "
+ "throwing IllegalStateException "
+ "because device does not exist in config", deviceId);
throw new IllegalStateException();
}
}
......@@ -168,6 +174,9 @@ public class DeviceConfiguration implements DeviceProperties {
deviceConfigMap.get(deviceId).ip);
return deviceConfigMap.get(deviceId).ip;
} else {
log.warn("getRouterIp for device {} "
+ "throwing IllegalStateException "
+ "because device does not exist in config", deviceId);
throw new IllegalStateException();
}
}
......@@ -187,6 +196,9 @@ public class DeviceConfiguration implements DeviceProperties {
deviceConfigMap.get(deviceId).isEdge);
return deviceConfigMap.get(deviceId).isEdge;
} else {
log.warn("isEdgeDevice for device {} "
+ "throwing IllegalStateException "
+ "because device does not exist in config", deviceId);
throw new IllegalStateException();
}
}
......
......@@ -217,6 +217,11 @@ public class RoutingRulePopulator {
// If the next hop is the destination router, do PHP
if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
log.debug("populateMplsRule: Installing MPLS forwarding objective for "
+ "label {} in switch {} with PHP",
config.getSegmentId(destSwId),
deviceId);
ForwardingObjective.Builder fwdObjBosBuilder =
getMplsForwardingObjective(deviceId,
destSwId,
......@@ -237,6 +242,11 @@ public class RoutingRulePopulator {
return false;
}
} else {
log.debug("Installing MPLS forwarding objective for "
+ "label {} in switch {} without PHP",
config.getSegmentId(destSwId),
deviceId);
ForwardingObjective.Builder fwdObjBosBuilder =
getMplsForwardingObjective(deviceId,
destSwId,
......@@ -264,8 +274,6 @@ public class RoutingRulePopulator {
.makePermanent()).withSelector(selector)
.withPriority(100))
.withFlag(ForwardingObjective.Flag.SPECIFIC);
log.debug("Installing MPLS forwarding objective in switch {}",
deviceId);
srManager.flowObjectiveService.forward(deviceId,
fwdObjBuilder.add());
rulePopulationCounter.incrementAndGet();
......
......@@ -19,16 +19,12 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.onlab.packet.MplsLabel;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flowobjective.DefaultNextObjective;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.net.link.LinkService;
import org.onosproject.store.service.EventuallyConsistentMap;
/**
* Default ECMP group handler creation module for an edge device.
......@@ -53,8 +49,11 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler {
ApplicationId appId,
DeviceProperties config,
LinkService linkService,
FlowObjectiveService flowObjService) {
super(deviceId, appId, config, linkService, flowObjService);
FlowObjectiveService flowObjService,
EventuallyConsistentMap<
NeighborSetNextObjectiveStoreKey,
Integer> nsNextObjStore) {
super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
}
@Override
......@@ -108,7 +107,7 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler {
@Override
protected void newPortToExistingNeighbor(Link newNeighborLink) {
log.debug("New port to existing neighbor: Updating "
/*log.debug("New port to existing neighbor: Updating "
+ "groups for edge device {}", deviceId);
addNeighborAtPort(newNeighborLink.dst().deviceId(),
newNeighborLink.src().port());
......@@ -129,7 +128,7 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler {
mplsLabel(ns.getEdgeLabel()));
}
Integer nextId = deviceNextObjectiveIds.get(getGroupKey(ns));
Integer nextId = deviceNextObjectiveIds.get(ns);
if (nextId != null) {
NextObjective.Builder nextObjBuilder = DefaultNextObjective
.builder().withId(nextId)
......@@ -140,7 +139,7 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler {
NextObjective nextObjective = nextObjBuilder.add();
flowObjectiveService.next(deviceId, nextObjective);
}
}
}*/
}
@Override
......
......@@ -18,16 +18,12 @@ package org.onosproject.segmentrouting.grouphandler;
import java.util.HashSet;
import java.util.Set;
import org.onlab.packet.MplsLabel;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flowobjective.DefaultNextObjective;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.net.link.LinkService;
import org.onosproject.store.service.EventuallyConsistentMap;
/**
* Default ECMP group handler creation module for a transit device.
......@@ -47,8 +43,11 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler {
ApplicationId appId,
DeviceProperties config,
LinkService linkService,
FlowObjectiveService flowObjService) {
super(deviceId, appId, config, linkService, flowObjService);
FlowObjectiveService flowObjService,
EventuallyConsistentMap<
NeighborSetNextObjectiveStoreKey,
Integer> nsNextObjStore) {
super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
}
@Override
......@@ -96,7 +95,7 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler {
@Override
protected void newPortToExistingNeighbor(Link newNeighborLink) {
log.debug("New port to existing neighbor: Updating "
/*log.debug("New port to existing neighbor: Updating "
+ "groups for transit device {}", deviceId);
addNeighborAtPort(newNeighborLink.dst().deviceId(),
newNeighborLink.src().port());
......@@ -118,7 +117,7 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler {
}
Integer nextId = deviceNextObjectiveIds.get(getGroupKey(ns));
Integer nextId = deviceNextObjectiveIds.get(ns);
if (nextId != null) {
NextObjective.Builder nextObjBuilder = DefaultNextObjective
.builder().withId(nextId)
......@@ -129,7 +128,7 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler {
NextObjective nextObjective = nextObjBuilder.add();
flowObjectiveService.next(deviceId, nextObjective);
}
}
}*/
}
@Override
......
/*
* Copyright 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 java.util.Objects;
import org.onosproject.net.DeviceId;
/**
* Class definition of Key for Neighborset to NextObjective store.
*/
public class NeighborSetNextObjectiveStoreKey {
private final DeviceId deviceId;
private final NeighborSet ns;
public NeighborSetNextObjectiveStoreKey(DeviceId deviceId,
NeighborSet ns) {
this.deviceId = deviceId;
this.ns = ns;
}
public DeviceId deviceId() {
return this.deviceId;
}
public NeighborSet neighborSet() {
return this.ns;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof NeighborSetNextObjectiveStoreKey)) {
return false;
}
NeighborSetNextObjectiveStoreKey that =
(NeighborSetNextObjectiveStoreKey) o;
return (Objects.equals(this.deviceId, that.deviceId) &&
Objects.equals(this.ns, that.ns));
}
// The list of neighbor ids and label are used for comparison.
@Override
public int hashCode() {
int result = 17;
result = 31 * result + Objects.hashCode(this.deviceId)
+ Objects.hashCode(this.ns);
return result;
}
@Override
public String toString() {
return "Device: " + deviceId + " Neighborset: " + ns;
}
}
......@@ -27,6 +27,7 @@ import java.util.List;
import org.onlab.packet.MplsLabel;
import org.onosproject.core.ApplicationId;
import org.onosproject.segmentrouting.grouphandler.GroupBucketIdentifier.BucketOutputType;
import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficTreatment;
......@@ -58,8 +59,11 @@ public class PolicyGroupHandler extends DefaultGroupHandler {
ApplicationId appId,
DeviceProperties config,
LinkService linkService,
FlowObjectiveService flowObjService) {
super(deviceId, appId, config, linkService, flowObjService);
FlowObjectiveService flowObjService,
EventuallyConsistentMap<
NeighborSetNextObjectiveStoreKey,
Integer> nsNextObjStore) {
super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
}
public PolicyGroupIdentifier createPolicyGroupChain(String id,
......
......@@ -15,6 +15,8 @@
*/
package org.onosproject.net.group;
import java.util.Collection;
import org.onosproject.core.GroupId;
import org.onosproject.net.DeviceId;
import org.onosproject.store.Store;
......@@ -162,4 +164,12 @@ public interface GroupStore extends Store<GroupEvent, GroupStoreDelegate> {
* @param operation the group operation failed
*/
void groupOperationFailed(DeviceId deviceId, GroupOperation operation);
/**
* Submits the group metrics to store for a given device ID.
*
* @param deviceId the device ID
* @param groupEntries the group entries as received from southbound
*/
void pushGroupMetrics(DeviceId deviceId, Collection<Group> groupEntries);
}
......
......@@ -15,7 +15,11 @@
*/
package org.onosproject.net.group.impl;
import com.google.common.collect.Sets;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collection;
import java.util.Collections;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -48,13 +52,6 @@ import org.onosproject.net.provider.AbstractProviderRegistry;
import org.onosproject.net.provider.AbstractProviderService;
import org.slf4j.Logger;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Provides implementation of the group service APIs.
*/
......@@ -316,131 +313,13 @@ public class GroupManager
store.groupOperationFailed(deviceId, operation);
}
private void groupMissing(Group group) {
checkValidity();
GroupProvider gp = getProvider(group.deviceId());
switch (group.state()) {
case PENDING_DELETE:
log.debug("Group {} delete confirmation from device {}",
group, group.deviceId());
store.removeGroupEntry(group);
break;
case ADDED:
case PENDING_ADD:
log.debug("Group {} is in store but not on device {}",
group, group.deviceId());
GroupOperation groupAddOp = GroupOperation.
createAddGroupOperation(group.id(),
group.type(),
group.buckets());
GroupOperations groupOps = new GroupOperations(
Collections.singletonList(groupAddOp));
gp.performGroupOperation(group.deviceId(), groupOps);
break;
default:
log.debug("Group {} has not been installed.", group);
break;
}
}
private void extraneousGroup(Group group) {
log.debug("Group {} is on device {} but not in store.",
group, group.deviceId());
checkValidity();
store.addOrUpdateExtraneousGroupEntry(group);
}
private void groupAdded(Group group) {
checkValidity();
log.trace("Group {} Added or Updated in device {}",
group, group.deviceId());
store.addOrUpdateGroupEntry(group);
}
@Override
public void pushGroupMetrics(DeviceId deviceId,
Collection<Group> groupEntries) {
log.trace("Received group metrics from device {}",
deviceId);
boolean deviceInitialAuditStatus =
store.deviceInitialAuditStatus(deviceId);
Set<Group> southboundGroupEntries =
Sets.newHashSet(groupEntries);
Set<Group> storedGroupEntries =
Sets.newHashSet(store.getGroups(deviceId));
Set<Group> extraneousStoredEntries =
Sets.newHashSet(store.getExtraneousGroups(deviceId));
log.trace("Displaying all ({}) southboundGroupEntries for device {}",
southboundGroupEntries.size(),
deviceId);
for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) {
Group group = it.next();
log.trace("Group {} in device {}", group, deviceId);
}
log.trace("Displaying all ({}) stored group entries for device {}",
storedGroupEntries.size(),
deviceId);
for (Iterator<Group> it1 = storedGroupEntries.iterator(); it1.hasNext();) {
Group group = it1.next();
log.trace("Stored Group {} for device {}", group, deviceId);
}
for (Iterator<Group> it2 = southboundGroupEntries.iterator(); it2.hasNext();) {
Group group = it2.next();
if (storedGroupEntries.remove(group)) {
// we both have the group, let's update some info then.
log.trace("Group AUDIT: group {} exists "
+ "in both planes for device {}",
group.id(), deviceId);
groupAdded(group);
it2.remove();
}
}
for (Group group : southboundGroupEntries) {
if (store.getGroup(group.deviceId(), group.id()) != null) {
// There is a group existing with the same id
// It is possible that group update is
// in progress while we got a stale info from switch
if (!storedGroupEntries.remove(store.getGroup(
group.deviceId(), group.id()))) {
log.warn("Group AUDIT: Inconsistent state:"
+ "Group exists in ID based table while "
+ "not present in key based table");
}
} else {
// there are groups in the switch that aren't in the store
log.trace("Group AUDIT: extraneous group {} exists "
+ "in data plane for device {}",
group.id(), deviceId);
extraneousStoredEntries.remove(group);
extraneousGroup(group);
}
}
for (Group group : storedGroupEntries) {
// there are groups in the store that aren't in the switch
log.trace("Group AUDIT: group {} missing "
+ "in data plane for device {}",
group.id(), deviceId);
groupMissing(group);
}
for (Group group : extraneousStoredEntries) {
// there are groups in the extraneous store that
// aren't in the switch
log.trace("Group AUDIT: clearing extransoeus group {} "
+ "from store for device {}",
group.id(), deviceId);
store.removeExtraneousGroupEntry(group);
}
if (!deviceInitialAuditStatus) {
log.debug("Group AUDIT: Setting device {} initial "
+ "AUDIT completed", deviceId);
store.deviceInitialAuditCompleted(deviceId, true);
}
checkValidity();
store.pushGroupMetrics(deviceId, groupEntries);
}
}
......@@ -450,10 +329,16 @@ public class GroupManager
public void event(DeviceEvent event) {
switch (event.type()) {
case DEVICE_REMOVED:
log.debug("Clearing device {} initial "
+ "AUDIT completed status as device is going down",
event.subject().id());
store.deviceInitialAuditCompleted(event.subject().id(), false);
case DEVICE_AVAILABILITY_CHANGED:
if (!deviceService.isAvailable(event.subject().id())) {
log.debug("GroupService DeviceListener: Received event {}."
+ "Device is no more available."
+ "Clearing device {} initial "
+ "AUDIT completed status",
event.type(),
event.subject().id());
store.deviceInitialAuditCompleted(event.subject().id(), false);
}
break;
default:
......
......@@ -315,6 +315,7 @@ public final class KryoNamespaces {
Instructions.DropInstruction.class,
Instructions.OutputInstruction.class,
Instructions.GroupInstruction.class,
Instructions.TableTypeTransition.class,
L0ModificationInstruction.class,
L0ModificationInstruction.L0SubType.class,
L0ModificationInstruction.ModLambdaInstruction.class,
......
......@@ -19,9 +19,12 @@ import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsent
import static org.slf4j.LoggerFactory.getLogger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
......@@ -54,6 +57,7 @@ import org.slf4j.Logger;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Sets;
/**
* Manages inventory of group entries using trivial in-memory implementation.
......@@ -583,4 +587,131 @@ public class SimpleGroupStore
getExtraneousGroupIdTable(deviceId).values());
}
@Override
public void pushGroupMetrics(DeviceId deviceId,
Collection<Group> groupEntries) {
boolean deviceInitialAuditStatus =
deviceInitialAuditStatus(deviceId);
Set<Group> southboundGroupEntries =
Sets.newHashSet(groupEntries);
Set<Group> storedGroupEntries =
Sets.newHashSet(getGroups(deviceId));
Set<Group> extraneousStoredEntries =
Sets.newHashSet(getExtraneousGroups(deviceId));
log.trace("pushGroupMetrics: Displaying all ({}) "
+ "southboundGroupEntries for device {}",
southboundGroupEntries.size(),
deviceId);
for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) {
Group group = it.next();
log.trace("Group {} in device {}", group, deviceId);
}
log.trace("Displaying all ({}) stored group entries for device {}",
storedGroupEntries.size(),
deviceId);
for (Iterator<Group> it1 = storedGroupEntries.iterator();
it1.hasNext();) {
Group group = it1.next();
log.trace("Stored Group {} for device {}", group, deviceId);
}
for (Iterator<Group> it2 = southboundGroupEntries.iterator(); it2.hasNext();) {
Group group = it2.next();
if (storedGroupEntries.remove(group)) {
// we both have the group, let's update some info then.
log.trace("Group AUDIT: group {} exists "
+ "in both planes for device {}",
group.id(), deviceId);
groupAdded(group);
it2.remove();
}
}
for (Group group : southboundGroupEntries) {
if (getGroup(group.deviceId(), group.id()) != null) {
// There is a group existing with the same id
// It is possible that group update is
// in progress while we got a stale info from switch
if (!storedGroupEntries.remove(getGroup(
group.deviceId(), group.id()))) {
log.warn("Group AUDIT: Inconsistent state:"
+ "Group exists in ID based table while "
+ "not present in key based table");
}
} else {
// there are groups in the switch that aren't in the store
log.trace("Group AUDIT: extraneous group {} exists "
+ "in data plane for device {}",
group.id(), deviceId);
extraneousStoredEntries.remove(group);
extraneousGroup(group);
}
}
for (Group group : storedGroupEntries) {
// there are groups in the store that aren't in the switch
log.trace("Group AUDIT: group {} missing "
+ "in data plane for device {}",
group.id(), deviceId);
groupMissing(group);
}
for (Group group : extraneousStoredEntries) {
// there are groups in the extraneous store that
// aren't in the switch
log.trace("Group AUDIT: clearing extransoeus group {} "
+ "from store for device {}",
group.id(), deviceId);
removeExtraneousGroupEntry(group);
}
if (!deviceInitialAuditStatus) {
log.debug("Group AUDIT: Setting device {} initial "
+ "AUDIT completed", deviceId);
deviceInitialAuditCompleted(deviceId, true);
}
}
private void groupMissing(Group group) {
switch (group.state()) {
case PENDING_DELETE:
log.debug("Group {} delete confirmation from device {}",
group, group.deviceId());
removeGroupEntry(group);
break;
case ADDED:
case PENDING_ADD:
case PENDING_UPDATE:
log.debug("Group {} is in store but not on device {}",
group, group.deviceId());
StoredGroupEntry existing = (groupEntriesById.get(
group.deviceId()) != null) ?
groupEntriesById.get(group.deviceId()).get(group.id()) :
null;
log.trace("groupMissing: group "
+ "entry {} in device {} moving "
+ "from {} to PENDING_ADD",
existing.id(),
existing.deviceId(),
existing.state());
existing.setState(Group.GroupState.PENDING_ADD);
notifyDelegate(new GroupEvent(GroupEvent.Type.GROUP_ADD_REQUESTED,
group));
break;
default:
log.debug("Group {} has not been installed.", group);
break;
}
}
private void extraneousGroup(Group group) {
log.debug("Group {} is on device {} but not in store.",
group, group.deviceId());
addOrUpdateExtraneousGroupEntry(group);
}
private void groupAdded(Group group) {
log.trace("Group {} Added or Updated in device {}",
group, group.deviceId());
addOrUpdateGroupEntry(group);
}
}
......
......@@ -195,11 +195,17 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
@Override
public void onSuccess(FlowRuleOperations ops) {
pass(fwd);
log.debug("Provisioned tables in {} with "
+ "forwarding rules for segment "
+ "router", deviceId);
}
@Override
public void onError(FlowRuleOperations ops) {
fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
log.warn("Failed to provision tables in {} with "
+ "forwarding rules for segment router",
deviceId);
}
}));
......@@ -228,6 +234,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
}
private void removeGroup(NextObjective nextObjective) {
log.debug("removeGroup in {}: for next objective id {}",
deviceId, nextObjective.id());
final GroupKey key = new DefaultGroupKey(
appKryo.serialize(nextObjective.id()));
groupService.removeGroup(deviceId, key, appId);
......@@ -293,6 +301,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
}
private void addBucketToGroup(NextObjective nextObjective) {
log.debug("addBucketToGroup in {}: for next objective id {}",
deviceId, nextObjective.id());
Collection<TrafficTreatment> treatments = nextObjective.next();
TrafficTreatment treatment = treatments.iterator().next();
final GroupKey key = new DefaultGroupKey(
......@@ -317,6 +327,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
}
private void removeBucketFromGroup(NextObjective nextObjective) {
log.debug("removeBucketFromGroup in {}: for next objective id {}",
deviceId, nextObjective.id());
NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
if (nextGroup != null) {
Collection<TrafficTreatment> treatments = nextObjective.next();
......@@ -369,7 +381,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
if ((ethType == null) ||
((((short) ethType.ethType()) != Ethernet.TYPE_IPV4) &&
(((short) ethType.ethType()) != Ethernet.MPLS_UNICAST))) {
log.debug("processSpecific: Unsupported "
log.warn("processSpecific: Unsupported "
+ "forwarding objective criteraia");
fail(fwd, ObjectiveError.UNSUPPORTED);
return Collections.emptySet();
......@@ -424,6 +436,10 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
}
treatmentBuilder.group(group.id());
log.debug("Adding OUTGROUP action");
} else {
log.warn("processSpecific: No associated next objective object");
fail(fwd, ObjectiveError.GROUPMISSING);
return Collections.emptySet();
}
}
......@@ -485,15 +501,39 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
return rules;
}
protected List<FlowRule> processVlanIdFilter(Criterion c,
FilteringObjective filt,
ApplicationId applicationId) {
List<FlowRule> rules = new ArrayList<FlowRule>();
VlanIdCriterion v = (VlanIdCriterion) c;
log.debug("adding rule for VLAN: {}", v.vlanId());
TrafficSelector.Builder selector = DefaultTrafficSelector
.builder();
TrafficTreatment.Builder treatment = DefaultTrafficTreatment
.builder();
PortCriterion p = (PortCriterion) filt.key();
if (v.vlanId() != VlanId.NONE) {
selector.matchVlanId(v.vlanId());
selector.matchInPort(p.port());
treatment.deferred().popVlan();
}
treatment.transition(tmacTableId);
FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
.withSelector(selector.build())
.withTreatment(treatment.build())
.withPriority(filt.priority()).fromApp(applicationId)
.makePermanent().forTable(vlanTableId).build();
rules.add(rule);
return rules;
}
private void processFilter(FilteringObjective filt, boolean install,
ApplicationId applicationId) {
// This driver only processes filtering criteria defined with switch
// ports as the key
PortCriterion p;
if (!filt.key().equals(Criteria.dummy())
&& filt.key().type() == Criterion.Type.IN_PORT) {
p = (PortCriterion) filt.key();
} else {
if (filt.key().equals(Criteria.dummy())
|| filt.key().type() != Criterion.Type.IN_PORT) {
log.warn("No key defined in filtering objective from app: {}. Not"
+ "processing filtering objective", applicationId);
fail(filt, ObjectiveError.UNKNOWN);
......@@ -509,24 +549,11 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
ops = install ? ops.add(rule) : ops.remove(rule);
}
} else if (c.type() == Criterion.Type.VLAN_VID) {
VlanIdCriterion v = (VlanIdCriterion) c;
log.debug("adding rule for VLAN: {}", v.vlanId());
TrafficSelector.Builder selector = DefaultTrafficSelector
.builder();
TrafficTreatment.Builder treatment = DefaultTrafficTreatment
.builder();
if (v.vlanId() != VlanId.NONE) {
selector.matchVlanId(v.vlanId());
selector.matchInPort(p.port());
treatment.deferred().popVlan();
for (FlowRule rule : processVlanIdFilter(c,
filt,
applicationId)) {
ops = install ? ops.add(rule) : ops.remove(rule);
}
treatment.transition(tmacTableId);
FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
.withSelector(selector.build())
.withTreatment(treatment.build())
.withPriority(filt.priority()).fromApp(applicationId)
.makePermanent().forTable(vlanTableId).build();
ops = install ? ops.add(rule) : ops.remove(rule);
} else if (c.type() == Criterion.Type.IPV4_DST) {
IPCriterion ip = (IPCriterion) c;
log.debug("adding rule for IP: {}", ip.ip());
......@@ -554,13 +581,15 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
@Override
public void onSuccess(FlowRuleOperations ops) {
pass(filt);
log.info("Provisioned tables for segment router");
log.debug("Provisioned tables in {} with fitering "
+ "rules for segment router", deviceId);
}
@Override
public void onError(FlowRuleOperations ops) {
fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
log.info("Failed to provision tables for segment router");
log.warn("Failed to provision tables in {} with "
+ "fitering rules for segment router", deviceId);
}
}));
}
......@@ -618,6 +647,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
@Override
public void event(GroupEvent event) {
if (event.type() == GroupEvent.Type.GROUP_ADDED) {
log.debug("InnerGroupListener: Group ADDED "
+ "event received in device {}", deviceId);
GroupKey key = event.subject().appCookie();
NextObjective obj = pendingGroups.getIfPresent(key);
......@@ -628,6 +659,9 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
pass(obj);
pendingGroups.invalidate(key);
}
} else if (event.type() == GroupEvent.Type.GROUP_ADD_FAILED) {
log.warn("InnerGroupListener: Group ADD "
+ "failed event received in device {}", deviceId);
}
}
}
......
......@@ -15,7 +15,6 @@
*/
package org.onosproject.driver.pipeline;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
......@@ -145,6 +144,10 @@ public class SpringOpenTTPDell extends SpringOpenTTP {
}
treatmentBuilder.group(group.id());
log.debug("Adding OUTGROUP action");
} else {
log.warn("processSpecific: No associated next objective object");
fail(fwd, ObjectiveError.GROUPMISSING);
return Collections.emptySet();
}
}
......@@ -175,43 +178,23 @@ public class SpringOpenTTPDell extends SpringOpenTTP {
protected List<FlowRule> processEthDstFilter(Criterion c,
FilteringObjective filt,
ApplicationId applicationId) {
List<FlowRule> rules = new ArrayList<FlowRule>();
EthCriterion e = (EthCriterion) c;
TrafficSelector.Builder selectorIp = DefaultTrafficSelector
.builder();
TrafficTreatment.Builder treatmentIp = DefaultTrafficTreatment
.builder();
// Store device termination Mac to be used in IP flow entries
EthCriterion e = (EthCriterion) c;
deviceTMac = e.mac();
selectorIp.matchEthDst(e.mac());
selectorIp.matchEthType(Ethernet.TYPE_IPV4);
treatmentIp.transition(ipv4UnicastTableId);
FlowRule ruleIp = DefaultFlowRule.builder().forDevice(deviceId)
.withSelector(selectorIp.build())
.withTreatment(treatmentIp.build())
.withPriority(filt.priority()).fromApp(applicationId)
.makePermanent().forTable(tmacTableId).build();
log.debug("adding IP ETH rule for MAC: {}", e.mac());
rules.add(ruleIp);
TrafficSelector.Builder selectorMpls = DefaultTrafficSelector
.builder();
TrafficTreatment.Builder treatmentMpls = DefaultTrafficTreatment
.builder();
selectorMpls.matchEthDst(e.mac());
selectorMpls.matchEthType(Ethernet.MPLS_UNICAST);
treatmentMpls.transition(mplsTableId);
FlowRule ruleMpls = DefaultFlowRule.builder()
.forDevice(deviceId).withSelector(selectorMpls.build())
.withTreatment(treatmentMpls.build())
.withPriority(filt.priority()).fromApp(applicationId)
.makePermanent().forTable(tmacTableId).build();
log.debug("adding MPLS ETH rule for MAC: {}", e.mac());
rules.add(ruleMpls);
return rules;
log.debug("For now not adding any TMAC rules "
+ "into Dell switches as it is ignoring");
return Collections.emptyList();
}
@Override
protected List<FlowRule> processVlanIdFilter(Criterion c,
FilteringObjective filt,
ApplicationId applicationId) {
log.debug("For now not adding any VLAN rules "
+ "into Dell switches as it is ignoring");
return Collections.emptyList();
}
}
\ No newline at end of file
......
......@@ -37,13 +37,6 @@
<behaviour api="org.onosproject.net.behaviour.Pipeliner"
impl="org.onosproject.driver.pipeline.SpringOpenTTPDell"/>
</driver>
<driver name="cpqd" manufacturer="Stanford University, Ericsson Research and CPqD Research"
hwVersion="OpenFlow 1.3 Reference Userspace Switch" swVersion=".*">
<behaviour api="org.onosproject.net.behaviour.Pipeliner"
impl="org.onosproject.driver.pipeline.SpringOpenTTP"/>
<behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
impl="org.onosproject.driver.handshaker.OFSwitchImplSpringOpenTTP"/>
</driver>
<driver name="linc-oe" extends="default"
manufacturer="FlowForwarding.org" hwVersion="Unknown" swVersion="LINC-OE OpenFlow Software Switch 1.1">
<behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
......
......@@ -295,7 +295,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
return;
}
if (m.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
log.warn("Stats reply indicates more stats from sw {} for "
log.debug("Stats reply indicates more stats from sw {} for "
+ "port description",
h.getSwitchInfoString());
h.portDescReplies.add((OFPortDescStatsReply)m);
......