diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java index 3a2d243510..c5bd6baeb5 100644 --- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java +++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java @@ -24,7 +24,6 @@ import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.Link; import org.onosproject.net.MastershipRole; -import org.onosproject.net.flow.FlowRule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,7 +37,8 @@ import static com.google.common.base.Preconditions.checkNotNull; public class DefaultRoutingHandler { - private static Logger log = LoggerFactory.getLogger(DefaultRoutingHandler.class); + private static Logger log = LoggerFactory + .getLogger(DefaultRoutingHandler.class); private SegmentRoutingManager srManager; private RoutingRulePopulator rulePopulator; @@ -56,7 +56,8 @@ public class DefaultRoutingHandler { // population process started. STARTED, - // population process was aborted due to errors, mostly for groups not found. + // population process was aborted due to errors, mostly for groups not + // found. ABORTED, // population process was finished successfully. @@ -89,8 +90,7 @@ public class DefaultRoutingHandler { log.info("Starts to populate routing rules"); for (Device sw : srManager.deviceService.getDevices()) { - if (srManager.mastershipService. - getLocalRole(sw.id()) != MastershipRole.MASTER) { + if (srManager.mastershipService.getLocalRole(sw.id()) != MastershipRole.MASTER) { continue; } @@ -323,11 +323,11 @@ public class DefaultRoutingHandler { private boolean populateEcmpRoutingRules(DeviceId destSw, ECMPShortestPathGraph ecmpSPG) { - HashMap>>> switchVia = - ecmpSPG.getAllLearnedSwitchesAndVia(); + HashMap>>> switchVia = ecmpSPG + .getAllLearnedSwitchesAndVia(); for (Integer itrIdx : switchVia.keySet()) { - HashMap>> swViaMap = - switchVia.get(itrIdx); + HashMap>> swViaMap = switchVia + .get(itrIdx); for (DeviceId targetSw : swViaMap.keySet()) { Set nextHops = new HashSet<>(); @@ -347,15 +347,17 @@ public class DefaultRoutingHandler { return true; } - private boolean populateEcmpRoutingRulePartial(DeviceId targetSw, DeviceId destSw, - Set nextHops) { + private boolean populateEcmpRoutingRulePartial(DeviceId targetSw, + DeviceId destSw, + Set nextHops) { boolean result; if (nextHops.isEmpty()) { nextHops.add(destSw); } - // If both target switch and dest switch are edge routers, then set IP rule + // 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 subnets = config.getSubnets(destSw); @@ -374,7 +376,7 @@ public class DefaultRoutingHandler { return false; } - // If the target switch is an edge router, then set IP rules for the router IP. + // TODO: If the target switch is an edge router, then set IP rules for the router IP. } else if (config.isEdgeDevice(targetSw)) { Ip4Address routerIp = config.getRouterIp(destSw); IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH); @@ -383,7 +385,7 @@ public class DefaultRoutingHandler { return false; } - // If the target switch is an transit router, then set MPLS rules only. + // TODO: If the target switch is an transit router, then set MPLS rules only. } else if (!config.isEdgeDevice(targetSw)) { result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops); if (!result) { @@ -395,38 +397,25 @@ public class DefaultRoutingHandler { } /** - * Populates table miss entries for all tables, and pipeline rules for - * VLAN and TACM tables. + * Populates table miss entries for all tables, and pipeline rules for VLAN + * and TACM tables. * * @param deviceId Switch ID to set the rules */ public void populateTtpRules(DeviceId deviceId) { - - rulePopulator.populateTableMissEntry(deviceId, FlowRule.Type.VLAN, - true, false, false, FlowRule.Type.DEFAULT); - rulePopulator.populateTableMissEntry(deviceId, FlowRule.Type.ETHER, - true, false, false, FlowRule.Type.DEFAULT); - rulePopulator.populateTableMissEntry(deviceId, FlowRule.Type.IP, - false, true, true, FlowRule.Type.ACL); - rulePopulator.populateTableMissEntry(deviceId, FlowRule.Type.MPLS, - false, true, true, FlowRule.Type.ACL); - rulePopulator.populateTableMissEntry(deviceId, FlowRule.Type.ACL, - false, false, false, FlowRule.Type.DEFAULT); - rulePopulator.populateTableVlan(deviceId); rulePopulator.populateTableTMac(deviceId); } /** - * Start the flow rule population process if it was never started. - * The process finishes successfully when all flow rules are set and - * stops with ABORTED status when any groups required for flows is not - * set yet. + * Start the flow rule population process if it was never started. The + * process finishes successfully when all flow rules are set and stops with + * ABORTED status when any groups required for flows is not set yet. */ public void startPopulationProcess() { synchronized (populationStatus) { - if (populationStatus == Status.IDLE || - populationStatus == Status.SUCCEEDED) { + if (populationStatus == Status.IDLE + || populationStatus == Status.SUCCEEDED) { populationStatus = Status.STARTED; populateAllRoutingRules(); } @@ -441,7 +430,8 @@ public class DefaultRoutingHandler { synchronized (populationStatus) { if (populationStatus == Status.ABORTED) { populationStatus = Status.STARTED; - // TODO: we need to restart from the point aborted instead of restarting. + // TODO: we need to restart from the point aborted instead of + // restarting. populateAllRoutingRules(); } } diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/NetworkConfigHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/NetworkConfigHandler.java new file mode 100644 index 0000000000..d346817819 --- /dev/null +++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/NetworkConfigHandler.java @@ -0,0 +1,157 @@ +/* + * 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; + +import com.google.common.collect.Lists; + +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip4Prefix; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MacAddress; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.PortNumber; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Set; + +/** + * This class is temporary class and used only for test. + * It will be replaced with "real" Network Config Manager. + * + * TODO: Knock off this wrapper and directly use DeviceConfiguration class + */ + +public class NetworkConfigHandler { + + private static Logger log = LoggerFactory.getLogger(NetworkConfigHandler.class); + private SegmentRoutingManager srManager; + private DeviceConfiguration deviceConfig; + + public NetworkConfigHandler(SegmentRoutingManager srManager, + DeviceConfiguration deviceConfig) { + this.srManager = srManager; + this.deviceConfig = deviceConfig; + } + + public List getGatewayIpAddress(DeviceId deviceId) { + return this.deviceConfig.getSubnetGatewayIps(deviceId); + } + + public IpPrefix getRouterIpAddress(DeviceId deviceId) { + return IpPrefix.valueOf(deviceConfig.getRouterIp(deviceId), 32); + } + + public MacAddress getRouterMacAddress(DeviceId deviceId) { + return deviceConfig.getDeviceMac(deviceId); + } + + public boolean inSameSubnet(DeviceId deviceId, Ip4Address destIp) { + + List subnets = getSubnetInfo(deviceId); + if (subnets == null) { + return false; + } + + return subnets.stream() + .anyMatch((subnet) -> subnet.contains(destIp)); + } + + public boolean inSameSubnet(Ip4Address address, int sid) { + DeviceId deviceId = deviceConfig.getDeviceId(sid); + if (deviceId == null) { + log.warn("Cannot find a device for SID {}", sid); + return false; + } + + return inSameSubnet(deviceId, address); + } + + public List getSubnetInfo(DeviceId deviceId) { + return deviceConfig.getSubnets(deviceId); + } + + public int getMplsId(DeviceId deviceId) { + return deviceConfig.getSegmentId(deviceId); + } + + public int getMplsId(MacAddress routerMac) { + return deviceConfig.getSegmentId(routerMac); + } + + public int getMplsId(Ip4Address routerIpAddress) { + return deviceConfig.getSegmentId(routerIpAddress); + } + + public boolean isEcmpNotSupportedInTransit(DeviceId deviceId) { + //TODO: temporarily changing to true to test with Dell + return true; + } + + public boolean isTransitRouter(DeviceId deviceId) { + return !(deviceConfig.isEdgeDevice(deviceId)); + } + + + public boolean isEdgeRouter(DeviceId deviceId) { + return deviceConfig.isEdgeDevice(deviceId); + } + + private List getPortsToNeighbors(DeviceId deviceId, List fwdSws) { + + List portNumbers = Lists.newArrayList(); + + Set links = srManager.linkService.getDeviceEgressLinks(deviceId); + for (Link link: links) { + for (DeviceId swId: fwdSws) { + if (link.dst().deviceId().equals(swId)) { + portNumbers.add(link.src().port()); + break; + } + } + } + + return portNumbers; + } + + public List getPortsToDevice(DeviceId deviceId) { + List portNumbers = Lists.newArrayList(); + + Set links = srManager.linkService.getDeviceEgressLinks(deviceId); + for (Link link: links) { + if (link.dst().deviceId().equals(deviceId)) { + portNumbers.add(link.src().port()); + } + } + + return portNumbers; + } + + + public Ip4Address getDestinationRouterAddress(Ip4Address destIpAddress) { + return deviceConfig.getRouterIpAddressForASubnetHost(destIpAddress); + } + + public DeviceId getDeviceId(Ip4Address ip4Address) { + return deviceConfig.getDeviceId(ip4Address); + } + + public MacAddress getRouterMac(Ip4Address targetAddress) { + return deviceConfig.getRouterMacForAGatewayIp(targetAddress); + } +} diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java index c4db26cad7..2d2102bbb3 100644 --- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java +++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java @@ -21,23 +21,25 @@ import org.onlab.packet.Ip4Prefix; import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; import org.onlab.packet.MplsLabel; +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.PortNumber; -import org.onosproject.net.flow.DefaultFlowRule; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; -import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.TrafficTreatment; -import org.onosproject.net.group.DefaultGroupKey; -import org.onosproject.net.group.Group; +import org.onosproject.net.flow.criteria.Criteria; +import org.onosproject.net.flowobjective.DefaultFilteringObjective; +import org.onosproject.net.flowobjective.DefaultForwardingObjective; +import org.onosproject.net.flowobjective.FilteringObjective; +import org.onosproject.net.flowobjective.ForwardingObjective; +import org.onosproject.net.flowobjective.ForwardingObjective.Builder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; @@ -46,7 +48,8 @@ import static com.google.common.base.Preconditions.checkNotNull; public class RoutingRulePopulator { - private static final Logger log = LoggerFactory.getLogger(RoutingRulePopulator.class); + private static final Logger log = LoggerFactory + .getLogger(RoutingRulePopulator.class); private AtomicLong rulePopulationCounter; private SegmentRoutingManager srManager; @@ -77,7 +80,8 @@ public class RoutingRulePopulator { } /** - * Populates IP flow rules for specific hosts directly connected to the switch. + * Populates IP flow rules for specific hosts directly connected to the + * switch. * * @param deviceId switch ID to set the rules * @param hostIp host IP address @@ -99,12 +103,15 @@ public class RoutingRulePopulator { TrafficTreatment treatment = tbuilder.build(); TrafficSelector selector = sbuilder.build(); - FlowRule f = new DefaultFlowRule(deviceId, selector, treatment, 100, - srManager.appId, 600, false, FlowRule.Type.IP); + ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective + .builder().fromApp(srManager.appId).makePermanent() + .withSelector(selector).withTreatment(treatment) + .withPriority(100).withFlag(ForwardingObjective.Flag.SPECIFIC); - srManager.flowRuleService.applyFlowRules(f); + log.debug("Installing IPv4 forwarding objective " + + "for host {} in switch {}", hostIp, deviceId); + srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add()); rulePopulationCounter.incrementAndGet(); - log.debug("Flow rule {} is set to switch {}", f, deviceId); } /** @@ -116,11 +123,12 @@ public class RoutingRulePopulator { * @param nextHops next hop switch ID list * @return true if all rules are set successfully, false otherwise */ - public boolean populateIpRuleForSubnet(DeviceId deviceId, List subnets, - DeviceId destSw, Set nextHops) { + public boolean populateIpRuleForSubnet(DeviceId deviceId, + List subnets, + DeviceId destSw, + Set nextHops) { - //List subnets = extractSubnet(subnetInfo); - for (IpPrefix subnet: subnets) { + for (IpPrefix subnet : subnets) { if (!populateIpRuleForRouter(deviceId, subnet, destSw, nextHops)) { return false; } @@ -138,8 +146,9 @@ public class RoutingRulePopulator { * @param nextHops next hop switch ID list * @return true if all rules are set successfully, false otherwise */ - public boolean populateIpRuleForRouter(DeviceId deviceId, IpPrefix ipPrefix, - DeviceId destSw, Set nextHops) { + public boolean populateIpRuleForRouter(DeviceId deviceId, + IpPrefix ipPrefix, DeviceId destSw, + Set nextHops) { TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); @@ -149,7 +158,8 @@ public class RoutingRulePopulator { NeighborSet ns = null; - //If the next hop is the same as the final destination, then MPLS label is not set. + // If the next hop is the same as the final destination, then MPLS label + // is not set. if (nextHops.size() == 1 && nextHops.toArray()[0].equals(destSw)) { tbuilder.decNwTtl(); ns = new NeighborSet(nextHops); @@ -158,34 +168,28 @@ public class RoutingRulePopulator { ns = new NeighborSet(nextHops, config.getSegmentId(destSw)); } - DefaultGroupKey groupKey = (DefaultGroupKey) srManager.getGroupKey(ns); - if (groupKey == null) { - log.warn("Group key is not found for ns {}", ns); - return false; - } - Group group = srManager.groupService.getGroup(deviceId, groupKey); - if (group != null) { - tbuilder.group(group.id()); - } else { - log.warn("No group found for NeighborSet {} from {} to {}", - ns, deviceId, destSw); - return false; - } - TrafficTreatment treatment = tbuilder.build(); TrafficSelector selector = sbuilder.build(); - FlowRule f = new DefaultFlowRule(deviceId, selector, treatment, 100, - srManager.appId, 600, false, FlowRule.Type.IP); - - srManager.flowRuleService.applyFlowRules(f); + ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective + .builder() + .fromApp(srManager.appId) + .makePermanent() + .nextStep(srManager.getNextObjectiveId(deviceId, ns)) + .withTreatment(treatment) + .withSelector(selector) + .withPriority(100) + .withFlag(ForwardingObjective.Flag.SPECIFIC); + log.debug("Installing IPv4 forwarding objective " + + "for router IP/subnet {} in switch {}", + ipPrefix, + deviceId); + srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add()); rulePopulationCounter.incrementAndGet(); - log.debug("IP flow rule {} is set to switch {}", f, deviceId); return true; } - /** * Populates MPLS flow rules to all transit routers. * @@ -194,35 +198,53 @@ public class RoutingRulePopulator { * @param nextHops next hops switch ID list * @return true if all rules are set successfully, false otherwise */ - public boolean populateMplsRule(DeviceId deviceId, DeviceId destSwId, Set nextHops) { + public boolean populateMplsRule(DeviceId deviceId, DeviceId destSwId, + Set nextHops) { TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); - Collection treatments = new ArrayList<>(); + List fwdObjBuilders = new ArrayList(); // TODO Handle the case of Bos == false sbuilder.matchMplsLabel(MplsLabel.mplsLabel(config.getSegmentId(destSwId))); sbuilder.matchEthType(Ethernet.MPLS_UNICAST); - //If the next hop is the destination router, do PHP + // If the next hop is the destination router, do PHP if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) { - TrafficTreatment treatmentBos = - getMplsTreatment(deviceId, destSwId, nextHops, true, true); - TrafficTreatment treatment = - getMplsTreatment(deviceId, destSwId, nextHops, true, false); - if (treatmentBos != null) { - treatments.add(treatmentBos); + ForwardingObjective.Builder fwdObjBosBuilder = + getMplsForwardingObjective(deviceId, + destSwId, + nextHops, + true, + true); + // TODO: Check with Sangho on why we need this + ForwardingObjective.Builder fwdObjNoBosBuilder = + getMplsForwardingObjective(deviceId, + destSwId, + nextHops, + true, + false); + if (fwdObjBosBuilder != null) { + fwdObjBuilders.add(fwdObjBosBuilder); } else { log.warn("Failed to set MPLS rules."); return false; } } else { - TrafficTreatment treatmentBos = - getMplsTreatment(deviceId, destSwId, nextHops, false, true); - TrafficTreatment treatment = - getMplsTreatment(deviceId, destSwId, nextHops, false, false); - - if (treatmentBos != null) { - treatments.add(treatmentBos); + ForwardingObjective.Builder fwdObjBosBuilder = + getMplsForwardingObjective(deviceId, + destSwId, + nextHops, + false, + true); + // TODO: Check with Sangho on why we need this + ForwardingObjective.Builder fwdObjNoBosBuilder = + getMplsForwardingObjective(deviceId, + destSwId, + nextHops, + false, + false); + if (fwdObjBosBuilder != null) { + fwdObjBuilders.add(fwdObjBosBuilder); } else { log.warn("Failed to set MPLS rules."); return false; @@ -230,34 +252,42 @@ public class RoutingRulePopulator { } TrafficSelector selector = sbuilder.build(); - for (TrafficTreatment treatment: treatments) { - FlowRule f = new DefaultFlowRule(deviceId, selector, treatment, 100, - srManager.appId, 600, false, FlowRule.Type.MPLS); - srManager.flowRuleService.applyFlowRules(f); + for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) { + ((Builder) ((Builder) fwdObjBuilder.fromApp(srManager.appId) + .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(); - log.debug("MPLS rule {} is set to {}", f, deviceId); } return true; } + private ForwardingObjective.Builder getMplsForwardingObjective(DeviceId deviceId, + DeviceId destSw, + Set nextHops, + boolean phpRequired, + boolean isBos) { - private TrafficTreatment getMplsTreatment(DeviceId deviceId, DeviceId destSw, - Set nextHops, - boolean phpRequired, boolean isBos) { + ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective + .builder().withFlag(ForwardingObjective.Flag.SPECIFIC); TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); if (phpRequired) { + log.debug("getMplsForwardingObjective: php required"); tbuilder.copyTtlIn(); if (isBos) { - tbuilder.popMpls(Ethernet.TYPE_IPV4) - .decNwTtl(); + tbuilder.popMpls(Ethernet.TYPE_IPV4).decNwTtl(); } else { - tbuilder.popMpls(Ethernet.MPLS_UNICAST) - .decMplsTtl(); + tbuilder.popMpls(Ethernet.MPLS_UNICAST).decMplsTtl(); } } else { + log.debug("getMplsForwardingObjective: php not required"); tbuilder.decMplsTtl(); } @@ -271,24 +301,14 @@ public class RoutingRulePopulator { tbuilder.setEthSrc(config.getDeviceMac(deviceId)) .setEthDst(config.getDeviceMac(nextHop)) .setOutput(link.src().port()); + fwdBuilder.withTreatment(tbuilder.build()); } else { NeighborSet ns = new NeighborSet(nextHops); - DefaultGroupKey groupKey = (DefaultGroupKey) srManager.getGroupKey(ns); - if (groupKey == null) { - log.warn("Group key is not found for ns {}", ns); - return null; - } - Group group = srManager.groupService.getGroup(deviceId, groupKey); - if (group != null) { - tbuilder.group(group.id()); - } else { - log.warn("No group found for ns {} key {} in {}", ns, - srManager.getGroupKey(ns), deviceId); - return null; - } + fwdBuilder.nextStep(srManager + .getNextObjectiveId(deviceId, ns)); } - return tbuilder.build(); + return fwdBuilder; } private boolean isECMPSupportedInTransitRouter() { @@ -298,109 +318,41 @@ public class RoutingRulePopulator { } /** - * Populates VLAN flows rules. - * All packets are forwarded to TMAC table. + * Populates VLAN flows rules. All packets are forwarded to TMAC table. * * @param deviceId switch ID to set the rules */ public void populateTableVlan(DeviceId deviceId) { - TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); - - tbuilder.transition(FlowRule.Type.ETHER); - - TrafficTreatment treatment = tbuilder.build(); - TrafficSelector selector = sbuilder.build(); - - FlowRule f = new DefaultFlowRule(deviceId, selector, treatment, 100, - srManager.appId, 600, false, FlowRule.Type.VLAN); - - srManager.flowRuleService.applyFlowRules(f); - - log.debug("Vlan flow rule {} is set to switch {}", f, deviceId); + FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); + fob.withKey(Criteria.matchInPort(PortNumber.ALL)) + .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()); } /** - * Populates TMAC table rules. - * IP packets are forwarded to IP table. - * MPLS packets are forwarded to MPLS table. + * Populates TMAC table rules. IP packets are forwarded to IP table. MPLS + * packets are forwarded to MPLS table. * * @param deviceId switch ID to set the rules */ public void populateTableTMac(DeviceId deviceId) { - // flow rule for IP packets - TrafficSelector selectorIp = DefaultTrafficSelector.builder() - .matchEthType(Ethernet.TYPE_IPV4) - .matchEthDst(config.getDeviceMac(deviceId)) - .build(); - TrafficTreatment treatmentIp = DefaultTrafficTreatment.builder() - .transition(FlowRule.Type.IP) - .build(); - - FlowRule flowIp = new DefaultFlowRule(deviceId, selectorIp, treatmentIp, 100, - srManager.appId, 600, false, FlowRule.Type.ETHER); - - srManager.flowRuleService.applyFlowRules(flowIp); - - // flow rule for MPLS packets - TrafficSelector selectorMpls = DefaultTrafficSelector.builder() - .matchEthType(Ethernet.MPLS_UNICAST) - .matchEthDst(config.getDeviceMac(deviceId)) - .build(); - TrafficTreatment treatmentMpls = DefaultTrafficTreatment.builder() - .transition(FlowRule.Type.MPLS) - .build(); - - FlowRule flowMpls = new DefaultFlowRule(deviceId, selectorMpls, treatmentMpls, 100, - srManager.appId, 600, false, FlowRule.Type.ETHER); - - srManager.flowRuleService.applyFlowRules(flowMpls); - - } - - /** - * Populates a table miss entry. - * - * @param deviceId switch ID to set rules - * @param tableToAdd table to set the rules - * @param toControllerNow flag to send packets to controller immediately - * @param toControllerWrite flag to send packets to controller at the end of pipeline - * @param toTable flag to send packets to a specific table - * @param tableToSend table type to send packets when the toTable flag is set - */ - public void populateTableMissEntry(DeviceId deviceId, FlowRule.Type tableToAdd, boolean toControllerNow, - boolean toControllerWrite, - boolean toTable, FlowRule.Type tableToSend) { - // TODO: Change arguments to EnumSet - TrafficSelector selector = DefaultTrafficSelector.builder() - .build(); - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); - - if (toControllerNow) { - tBuilder.setOutput(PortNumber.CONTROLLER); - } - - if (toControllerWrite) { - tBuilder.deferred().setOutput(PortNumber.CONTROLLER); - } - - if (toTable) { - tBuilder.transition(tableToSend); - } - - FlowRule flow = new DefaultFlowRule(deviceId, selector, tBuilder.build(), 0, - srManager.appId, 600, false, tableToAdd); - - srManager.flowRuleService.applyFlowRules(flow); - + FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); + fob.withKey(Criteria.matchInPort(PortNumber.ALL)) + .addCondition(Criteria.matchEthDst(config + .getDeviceMac(deviceId))); + fob.permit().fromApp(srManager.appId); + log.debug("populateTableVlan: Installing filtering objective for router mac"); + srManager.flowObjectiveService.filter(deviceId, fob.add()); } private Link selectOneLink(DeviceId srcId, Set destIds) { Set links = srManager.linkService.getDeviceEgressLinks(srcId); DeviceId destId = (DeviceId) destIds.toArray()[0]; - for (Link link: links) { + for (Link link : links) { if (link.dst().deviceId().equals(destId)) { return link; } diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java index 956fc1ec6e..b7167c8fdd 100644 --- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java +++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java @@ -36,12 +36,10 @@ import org.onosproject.net.Port; import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceService; -import org.onosproject.net.flow.FlowRuleService; +import org.onosproject.net.flowobjective.FlowObjectiveService; import org.onosproject.net.group.Group; import org.onosproject.net.group.GroupEvent; import org.onosproject.net.group.GroupKey; -import org.onosproject.net.group.GroupListener; -import org.onosproject.net.group.GroupService; import org.onosproject.net.host.HostService; import org.onosproject.net.intent.IntentService; import org.onosproject.net.link.LinkEvent; @@ -68,7 +66,8 @@ import java.util.concurrent.TimeUnit; @Component(immediate = true) public class SegmentRoutingManager { - private static Logger log = LoggerFactory.getLogger(SegmentRoutingManager.class); + private static Logger log = LoggerFactory + .getLogger(SegmentRoutingManager.class); @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected CoreService coreService; @@ -89,14 +88,11 @@ public class SegmentRoutingManager { protected DeviceService deviceService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected FlowRuleService flowRuleService; + protected FlowObjectiveService flowObjectiveService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected LinkService linkService; - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected GroupService groupService; - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected MastershipService mastershipService; protected ArpHandler arpHandler = null; @@ -110,12 +106,12 @@ public class SegmentRoutingManager { private InternalPacketProcessor processor = new InternalPacketProcessor(); private InternalEventHandler eventHandler = new InternalEventHandler(); - private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); + private ScheduledExecutorService executorService = Executors + .newScheduledThreadPool(1); private static ScheduledFuture eventHandlerFuture = null; private ConcurrentLinkedQueue eventQueue = new ConcurrentLinkedQueue(); - private Map groupHandlerMap - = new ConcurrentHashMap(); + private Map groupHandlerMap = new ConcurrentHashMap(); private NetworkConfigManager networkConfigService = new NetworkConfigManager();; @@ -125,7 +121,8 @@ public class SegmentRoutingManager { @Activate protected void activate() { - appId = coreService.registerApplication("org.onosproject.segmentrouting"); + appId = coreService + .registerApplication("org.onosproject.segmentrouting"); networkConfigService.init(); deviceConfiguration = new DeviceConfiguration(networkConfigService); arpHandler = new ArpHandler(this); @@ -136,25 +133,22 @@ public class SegmentRoutingManager { packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2); linkService.addListener(new InternalLinkListener()); - groupService.addListener(new InternalGroupListener()); deviceService.addListener(new InternalDeviceListener()); - for (Device device: deviceService.getDevices()) { - if (mastershipService. - getLocalRole(device.id()) == MastershipRole.MASTER) { - DefaultGroupHandler groupHandler = - DefaultGroupHandler.createGroupHandler(device.id(), - appId, deviceConfiguration, linkService, groupService); - groupHandler.createGroups(); + for (Device device : deviceService.getDevices()) { + if (mastershipService.getLocalRole(device.id()) == MastershipRole.MASTER) { + DefaultGroupHandler groupHandler = DefaultGroupHandler + .createGroupHandler(device.id(), appId, + deviceConfiguration, linkService, + flowObjectiveService); groupHandlerMap.put(device.id(), groupHandler); defaultRoutingHandler.populateTtpRules(device.id()); log.debug("Initiating default group handling for {}", device.id()); } else { log.debug("Activate: Local role {} " - + "is not MASTER for device {}", - mastershipService. - getLocalRole(device.id()), - device.id()); + + "is not MASTER for device {}", + mastershipService.getLocalRole(device.id()), + device.id()); } } @@ -177,13 +171,19 @@ public class SegmentRoutingManager { */ public GroupKey getGroupKey(NeighborSet ns) { - for (DefaultGroupHandler groupHandler: groupHandlerMap.values()) { + for (DefaultGroupHandler groupHandler : groupHandlerMap.values()) { return groupHandler.getGroupKey(ns); } return null; } + public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns) { + + return (groupHandlerMap.get(deviceId) != null) ? groupHandlerMap + .get(deviceId).getNextObjectiveId(ns) : -1; + } + private class InternalPacketProcessor implements PacketProcessor { @Override @@ -213,8 +213,8 @@ public class SegmentRoutingManager { private class InternalLinkListener implements LinkListener { @Override public void event(LinkEvent event) { - if (event.type() == LinkEvent.Type.LINK_ADDED || - event.type() == LinkEvent.Type.LINK_REMOVED) { + if (event.type() == LinkEvent.Type.LINK_ADDED + || event.type() == LinkEvent.Type.LINK_REMOVED) { scheduleEventHandlerIfNotScheduled(event); } } @@ -224,12 +224,10 @@ public class SegmentRoutingManager { @Override public void event(DeviceEvent event) { - if (mastershipService. - getLocalRole(event.subject().id()) != MastershipRole.MASTER) { + if (mastershipService.getLocalRole(event.subject().id()) != MastershipRole.MASTER) { log.debug("Local role {} is not MASTER for device {}", - mastershipService. - getLocalRole(event.subject().id()), - event.subject().id()); + mastershipService.getLocalRole(event.subject().id()), + event.subject().id()); return; } @@ -245,38 +243,18 @@ public class SegmentRoutingManager { } } - private class InternalGroupListener implements GroupListener { - - @Override - public void event(GroupEvent event) { - switch (event.type()) { - case GROUP_ADDED: - scheduleEventHandlerIfNotScheduled(event); - break; - case GROUP_ADD_REQUESTED: - log.info("Group add requested"); - break; - case GROUP_UPDATED: - break; - default: - log.warn("Unhandled group event type: {}", event.type()); - } - } - } - private void scheduleEventHandlerIfNotScheduled(Event event) { eventQueue.add(event); numOfEvents++; - if (eventHandlerFuture == null || - eventHandlerFuture.isDone()) { - eventHandlerFuture = executorService.schedule(eventHandler, - 100, TimeUnit.MILLISECONDS); + if (eventHandlerFuture == null || eventHandlerFuture.isDone()) { + eventHandlerFuture = executorService + .schedule(eventHandler, 100, TimeUnit.MILLISECONDS); numOfHandlerScheduled++; } log.trace("numOfEvents {}, numOfEventHanlderScheduled {}", numOfEvents, - numOfHandlerScheduled); + numOfHandlerScheduled); } @@ -301,25 +279,22 @@ public class SegmentRoutingManager { } } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) { processPortRemoved((Device) event.subject(), - ((DeviceEvent) event).port()); + ((DeviceEvent) event).port()); } else { log.warn("Unhandled event type: {}", event.type()); } } log.debug("numOfHandlerExecution {} numOfEventHanlderScheduled {} numOfEvents {}", - numOfHandlerExecution, numOfHandlerScheduled, numOfEvents); + numOfHandlerExecution, numOfHandlerScheduled, numOfEvents); } } - - private void processLinkAdded(Link link) { log.debug("A new link {} was added", link.toString()); - if (mastershipService. - getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) { - DefaultGroupHandler groupHandler = - groupHandlerMap.get(link.src().deviceId()); + if (mastershipService.getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) { + DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src() + .deviceId()); if (groupHandler != null) { groupHandler.linkUp(link); } @@ -332,7 +307,6 @@ public class SegmentRoutingManager { defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link); } - private void processGroupAdded(Group group) { log.debug("A new group with ID {} was added", group.id()); defaultRoutingHandler.resumePopulationProcess(); @@ -341,20 +315,14 @@ public class SegmentRoutingManager { private void processDeviceAdded(Device device) { log.debug("A new device with ID {} was added", device.id()); defaultRoutingHandler.populateTtpRules(device.id()); - DefaultGroupHandler dgh = DefaultGroupHandler.createGroupHandler( - device.id(), - appId, - deviceConfiguration, - linkService, - groupService); - dgh.createGroups(); + DefaultGroupHandler dgh = DefaultGroupHandler.createGroupHandler(device + .id(), appId, deviceConfiguration, linkService, flowObjectiveService); groupHandlerMap.put(device.id(), dgh); } private void processPortRemoved(Device device, Port port) { log.debug("Port {} was removed", port.toString()); - DefaultGroupHandler groupHandler = - groupHandlerMap.get(device.id()); + DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id()); if (groupHandler != null) { groupHandler.portDown(port.number()); } diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java index 0cd5743786..e54f51f532 100644 --- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java +++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java @@ -15,7 +15,6 @@ */ package org.onosproject.segmentrouting.grouphandler; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -26,10 +25,7 @@ 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.group.DefaultGroupBucket; -import org.onosproject.net.group.GroupBucket; -import org.onosproject.net.group.GroupBuckets; -import org.onosproject.net.group.GroupService; +import org.onosproject.net.flowobjective.FlowObjectiveService; import org.onosproject.net.link.LinkService; /** @@ -55,8 +51,8 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler { ApplicationId appId, DeviceProperties config, LinkService linkService, - GroupService groupService) { - super(deviceId, appId, config, linkService, groupService); + FlowObjectiveService flowObjService) { + super(deviceId, appId, config, linkService, flowObjService); } @Override @@ -130,7 +126,7 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler { .setMpls(MplsLabel. mplsLabel(ns.getEdgeLabel())); } - GroupBucket updatedBucket = DefaultGroupBucket. + /*GroupBucket updatedBucket = DefaultGroupBucket. createSelectGroupBucket(tBuilder.build()); GroupBuckets updatedBuckets = new GroupBuckets( Arrays.asList(updatedBucket)); @@ -140,7 +136,8 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler { getGroupKey(ns), updatedBuckets, getGroupKey(ns), - appId); + appId);*/ + //TODO: Use nextObjective APIs to update the next objective } } diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java index 0ac3728494..cb295db6fc 100644 --- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java +++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java @@ -20,10 +20,11 @@ import static org.slf4j.LoggerFactory.getLogger; import java.net.URI; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Random; import java.util.Set; import org.onlab.packet.MacAddress; @@ -35,25 +36,18 @@ import org.onosproject.net.Link; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.TrafficTreatment; -import org.onosproject.net.group.DefaultGroupBucket; -import org.onosproject.net.group.DefaultGroupDescription; +import org.onosproject.net.flowobjective.DefaultNextObjective; +import org.onosproject.net.flowobjective.FlowObjectiveService; +import org.onosproject.net.flowobjective.NextObjective; import org.onosproject.net.group.DefaultGroupKey; -import org.onosproject.net.group.Group; -import org.onosproject.net.group.GroupBucket; -import org.onosproject.net.group.GroupBuckets; -import org.onosproject.net.group.GroupDescription; -import org.onosproject.net.group.GroupEvent; import org.onosproject.net.group.GroupKey; -import org.onosproject.net.group.GroupListener; -import org.onosproject.net.group.GroupService; import org.onosproject.net.link.LinkService; import org.slf4j.Logger; /** - * Default ECMP group handler creation module. This - * component creates a set of ECMP groups for every neighbor - * that this device is connected to based on whether the - * current device is an edge device or a transit device. + * Default ECMP group handler creation module. This component creates a set of + * ECMP groups for every neighbor that this device is connected to based on + * whether the current device is an edge device or a transit device. */ public class DefaultGroupHandler { protected final Logger log = getLogger(getClass()); @@ -66,88 +60,78 @@ public class DefaultGroupHandler { protected final boolean isEdgeRouter; protected final MacAddress nodeMacAddr; protected LinkService linkService; - protected GroupService groupService; + protected FlowObjectiveService flowObjectiveService; protected HashMap> devicePortMap = new HashMap>(); protected HashMap portDeviceMap = new HashMap(); + protected HashMap deviceNextObjectiveIds = + new HashMap(); + protected Random rand = new Random(); - private GroupListener listener = new InternalGroupListener(); protected KryoNamespace.Builder kryo = new KryoNamespace.Builder() - .register(URI.class) - .register(HashSet.class) - .register(DeviceId.class) - .register(PortNumber.class) - .register(NeighborSet.class) - .register(PolicyGroupIdentifier.class) - .register(PolicyGroupParams.class) - .register(GroupBucketIdentifier.class) - .register(GroupBucketIdentifier.BucketOutputType.class); + .register(URI.class).register(HashSet.class) + .register(DeviceId.class).register(PortNumber.class) + .register(NeighborSet.class).register(PolicyGroupIdentifier.class) + .register(PolicyGroupParams.class) + .register(GroupBucketIdentifier.class) + .register(GroupBucketIdentifier.BucketOutputType.class); - protected DefaultGroupHandler(DeviceId deviceId, - ApplicationId appId, - DeviceProperties config, - LinkService linkService, - GroupService groupService) { + protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId, + DeviceProperties config, + LinkService linkService, + FlowObjectiveService flowObjService) { this.deviceId = checkNotNull(deviceId); this.appId = checkNotNull(appId); this.deviceConfig = checkNotNull(config); this.linkService = checkNotNull(linkService); - this.groupService = checkNotNull(groupService); allSegmentIds = checkNotNull(config.getAllDeviceSegmentIds()); nodeSegmentId = config.getSegmentId(deviceId); isEdgeRouter = config.isEdgeDevice(deviceId); nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId)); - - this.groupService.addListener(listener); + this.flowObjectiveService = flowObjService; populateNeighborMaps(); } /** - * Creates a group handler object based on the type of device. If - * device is of edge type it returns edge group handler, else it - * returns transit group handler. + * Creates a group handler object based on the type of device. If device is + * of edge type it returns edge group handler, else it returns transit group + * handler. * * @param deviceId device identifier * @param appId application identifier * @param config interface to retrieve the device properties * @param linkService link service object - * @param groupService group service object + * @param flowObjService flow objective service object * @return default group handler type */ public static DefaultGroupHandler createGroupHandler(DeviceId deviceId, - ApplicationId appId, - DeviceProperties config, - LinkService linkService, - GroupService groupService) { + ApplicationId appId, + DeviceProperties config, + LinkService linkService, + FlowObjectiveService flowObjService) { if (config.isEdgeDevice(deviceId)) { - return new DefaultEdgeGroupHandler(deviceId, - appId, - config, - linkService, - groupService); + return new DefaultEdgeGroupHandler(deviceId, appId, config, + linkService, flowObjService); } else { - return new DefaultTransitGroupHandler(deviceId, - appId, - config, - linkService, - groupService); + return new DefaultTransitGroupHandler(deviceId, appId, config, + linkService, flowObjService); } } /** - * Creates the auto created groups for this device based on the - * current snapshot of the topology. + * Creates the auto created groups for this device based on the current + * snapshot of the topology. */ - //Empty implementations to be overridden by derived classes + // Empty implementations to be overridden by derived classes public void createGroups() { } /** - * Performs group creation or update procedures when a new link - * is discovered on this device. + * Performs group creation or update procedures when a new link is + * discovered on this device. * * @param newLink new neighbor link */ @@ -158,16 +142,14 @@ public class DefaultGroupHandler { return; } - if (!newLink.src().deviceId().equals(deviceId)) { log.warn("linkUp: deviceId{} doesn't match with link src{}", - deviceId, - newLink.src().deviceId()); + deviceId, newLink.src().deviceId()); return; } - log.debug("Device {} linkUp at local port {} to neighbor {}", - deviceId, newLink.src().port(), newLink.dst().deviceId()); + log.debug("Device {} linkUp at local port {} to neighbor {}", deviceId, + newLink.src().port(), newLink.dst().deviceId()); if (devicePortMap.get(newLink.dst().deviceId()) == null) { // New Neighbor newNeighbor(newLink); @@ -178,8 +160,7 @@ public class DefaultGroupHandler { } /** - * Performs group recovery procedures when a port goes down - * on this device. + * Performs group recovery procedures when a port goes down on this device. * * @param port port number that has gone down */ @@ -188,35 +169,34 @@ public class DefaultGroupHandler { log.warn("portDown: unknown port"); return; } - log.debug("Device {} portDown {} to neighbor {}", - deviceId, port, portDeviceMap.get(port)); - Set nsSet = computeImpactedNeighborsetForPortEvent( - portDeviceMap.get(port), - devicePortMap.keySet()); + log.debug("Device {} portDown {} to neighbor {}", deviceId, port, + portDeviceMap.get(port)); + Set nsSet = computeImpactedNeighborsetForPortEvent(portDeviceMap + .get(port), + devicePortMap + .keySet()); for (NeighborSet ns : nsSet) { // Create the bucket to be removed - TrafficTreatment.Builder tBuilder = - DefaultTrafficTreatment.builder(); + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment + .builder(); tBuilder.setOutput(port) - .setEthDst(deviceConfig.getDeviceMac( - portDeviceMap.get(port))) - .setEthSrc(nodeMacAddr); + .setEthDst(deviceConfig.getDeviceMac(portDeviceMap + .get(port))).setEthSrc(nodeMacAddr); if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) { - tBuilder.pushMpls() - .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel())); + tBuilder.pushMpls().setMpls(MplsLabel.mplsLabel(ns + .getEdgeLabel())); } - GroupBucket removeBucket = DefaultGroupBucket. - createSelectGroupBucket(tBuilder.build()); - GroupBuckets removeBuckets = new GroupBuckets( - Arrays.asList(removeBucket)); - log.debug("portDown in device{}: " - + "groupService.removeBucketsFromGroup " - + "for neighborset{}", deviceId, ns); - groupService.removeBucketsFromGroup(deviceId, - getGroupKey(ns), - removeBuckets, - getGroupKey(ns), - appId); + /* + * GroupBucket removeBucket = DefaultGroupBucket. + * createSelectGroupBucket(tBuilder.build()); GroupBuckets + * removeBuckets = new GroupBuckets( Arrays.asList(removeBucket)); + * log.debug("portDown in device{}: " + + * "groupService.removeBucketsFromGroup " + "for neighborset{}", + * deviceId, ns); groupService.removeBucketsFromGroup(deviceId, + * getGroupKey(ns), removeBuckets, getGroupKey(ns), appId); + */ + //TODO: Use next objective API to update the previously created + //next objectives. } devicePortMap.get(portDeviceMap.get(port)).remove(port); @@ -224,33 +204,44 @@ public class DefaultGroupHandler { } /** - * Returns a group associated with the key. + * Returns the next objective associated with the neighborset. + * If there is no next objective for this neighborset, this API + * would create a next objective and return. * - * @param key cookie associated with the group - * @return group if found or null + * @param ns neighborset + * @return int if found or -1 */ - public Group getGroup(GroupKey key) { - return groupService.getGroup(deviceId, key); + public int getNextObjectiveId(NeighborSet ns) { + Integer nextId = deviceNextObjectiveIds.get(getGroupKey(ns)); + if (nextId == null) { + createGroupsFromNeighborsets(Collections.singleton(ns)); + nextId = deviceNextObjectiveIds.get(getGroupKey(ns)); + if (nextId == null) { + log.warn("getNextObjectiveId: unable to create next objective"); + return -1; + } + } + return nextId.intValue(); } - //Empty implementation + // Empty implementation protected void newNeighbor(Link newLink) { } - //Empty implementation + // Empty implementation protected void newPortToExistingNeighbor(Link newLink) { } - //Empty implementation - protected Set computeImpactedNeighborsetForPortEvent( - DeviceId impactedNeighbor, - Set updatedNeighbors) { + // Empty implementation + protected Set + computeImpactedNeighborsetForPortEvent(DeviceId impactedNeighbor, + Set updatedNeighbors) { return null; } private void populateNeighborMaps() { Set outgoingLinks = linkService.getDeviceEgressLinks(deviceId); - for (Link link:outgoingLinks) { + for (Link link : outgoingLinks) { if (link.type() != Link.Type.DIRECT) { continue; } @@ -258,7 +249,8 @@ public class DefaultGroupHandler { } } - protected void addNeighborAtPort(DeviceId neighborId, PortNumber portToNeighbor) { + protected void addNeighborAtPort(DeviceId neighborId, + PortNumber portToNeighbor) { // Update DeviceToPort database log.debug("Device {} addNeighborAtPort: neighbor {} at port {}", deviceId, neighborId, portToNeighbor); @@ -276,8 +268,7 @@ public class DefaultGroupHandler { } } - protected Set> - getPowerSetOfNeighbors(Set neighbors) { + protected Set> getPowerSetOfNeighbors(Set neighbors) { List list = new ArrayList(neighbors); Set> sets = new HashSet>(); // get the number of elements in the neighbors @@ -304,15 +295,14 @@ public class DefaultGroupHandler { return (deviceConfig.getSegmentId(deviceId) == sId); } - protected List getSegmentIdsTobePairedWithNeighborSet( - Set neighbors) { + protected List getSegmentIdsTobePairedWithNeighborSet(Set neighbors) { List nsSegmentIds = new ArrayList(); // Always pair up with no edge label - //If (neighbors.size() == 1) { + // If (neighbors.size() == 1) { nsSegmentIds.add(-1); - //} + // } // Filter out SegmentIds matching with the // nodes in the combo @@ -338,70 +328,28 @@ public class DefaultGroupHandler { protected void createGroupsFromNeighborsets(Set nsSet) { for (NeighborSet ns : nsSet) { - // Create the bucket array from the neighbor set - List buckets = new ArrayList(); + int nextId = flowObjectiveService.allocateNextId(); + NextObjective.Builder nextObjBuilder = DefaultNextObjective + .builder().withId(nextId) + .withType(NextObjective.Type.HASHED).fromApp(appId); for (DeviceId d : ns.getDeviceIds()) { for (PortNumber sp : devicePortMap.get(d)) { - TrafficTreatment.Builder tBuilder = - DefaultTrafficTreatment.builder(); + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment + .builder(); tBuilder.setOutput(sp) .setEthDst(deviceConfig.getDeviceMac(d)) .setEthSrc(nodeMacAddr); if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) { - tBuilder.pushMpls() - .setMpls(MplsLabel. - mplsLabel(ns.getEdgeLabel())); + tBuilder.pushMpls().setMpls(MplsLabel.mplsLabel(ns + .getEdgeLabel())); } - buckets.add(DefaultGroupBucket.createSelectGroupBucket( - tBuilder.build())); + nextObjBuilder.addTreatment(tBuilder.build()); } } - GroupBuckets groupBuckets = new GroupBuckets(buckets); - GroupDescription newGroupDesc = new DefaultGroupDescription( - deviceId, - Group.Type.SELECT, - groupBuckets, - getGroupKey(ns), - appId); - log.debug("createGroupsFromNeighborsets: " - + "groupService.addGroup for neighborset{}", ns); - groupService.addGroup(newGroupDesc); - } - } - protected void handleGroupEvent(GroupEvent event) { - switch (event.type()) { - case GROUP_ADDED: - log.debug("Received GROUP_ADDED from group service " - + "for device {} with group key{} with id{}", - event.subject().deviceId(), - event.subject().appCookie(), - event.subject().id()); - break; - case GROUP_UPDATED: - log.trace("Received GROUP_UPDATED from group service " - + "for device {} with group key{} with id{}", - event.subject().deviceId(), - event.subject().appCookie(), - event.subject().id()); - break; - case GROUP_REMOVED: - log.debug("Received GROUP_REMOVED from group service " - + "for device {} with group key{} with id{}", - event.subject().deviceId(), - event.subject().appCookie(), - event.subject().id()); - break; - default: - break; - } - } - - private class InternalGroupListener implements GroupListener { - - @Override - public void event(GroupEvent event) { - handleGroupEvent(event); + NextObjective nextObj = nextObjBuilder.add(); + flowObjectiveService.next(deviceId, nextObj); + deviceNextObjectiveIds.put(getGroupKey(ns), nextId); } } diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java index e053622114..67e9eef42c 100644 --- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java +++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java @@ -15,7 +15,6 @@ */ package org.onosproject.segmentrouting.grouphandler; -import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -25,10 +24,7 @@ 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.group.DefaultGroupBucket; -import org.onosproject.net.group.GroupBucket; -import org.onosproject.net.group.GroupBuckets; -import org.onosproject.net.group.GroupService; +import org.onosproject.net.flowobjective.FlowObjectiveService; import org.onosproject.net.link.LinkService; /** @@ -49,8 +45,8 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler { ApplicationId appId, DeviceProperties config, LinkService linkService, - GroupService groupService) { - super(deviceId, appId, config, linkService, groupService); + FlowObjectiveService flowObjService) { + super(deviceId, appId, config, linkService, flowObjService); } @Override @@ -118,7 +114,7 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler { .setMpls(MplsLabel. mplsLabel(ns.getEdgeLabel())); } - GroupBucket updatedBucket = DefaultGroupBucket. + /*GroupBucket updatedBucket = DefaultGroupBucket. createSelectGroupBucket(tBuilder.build()); GroupBuckets updatedBuckets = new GroupBuckets( Arrays.asList(updatedBucket)); @@ -128,7 +124,8 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler { getGroupKey(ns), updatedBuckets, getGroupKey(ns), - appId); + appId);*/ + //TODO: Use nextObjective APIs to update the next objective } } diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java index 9f35c742f8..d141ed1a52 100644 --- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java +++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java @@ -25,19 +25,13 @@ import java.util.List; import org.onlab.packet.MplsLabel; import org.onosproject.core.ApplicationId; -import org.onosproject.core.GroupId; import org.onosproject.segmentrouting.grouphandler.GroupBucketIdentifier.BucketOutputType; import org.onosproject.net.DeviceId; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.TrafficTreatment; -import org.onosproject.net.group.DefaultGroupBucket; -import org.onosproject.net.group.DefaultGroupDescription; +import org.onosproject.net.flowobjective.FlowObjectiveService; import org.onosproject.net.group.GroupBucket; -import org.onosproject.net.group.GroupBuckets; -import org.onosproject.net.group.GroupDescription; -import org.onosproject.net.group.GroupEvent; -import org.onosproject.net.group.GroupService; import org.onosproject.net.link.LinkService; import org.slf4j.Logger; @@ -58,14 +52,14 @@ public class PolicyGroupHandler extends DefaultGroupHandler { * @param appId application identifier * @param config interface to retrieve the device properties * @param linkService link service object - * @param groupService group service object + * @param flowObjService flow objective service object */ public PolicyGroupHandler(DeviceId deviceId, ApplicationId appId, DeviceProperties config, LinkService linkService, - GroupService groupService) { - super(deviceId, appId, config, linkService, groupService); + FlowObjectiveService flowObjService) { + super(deviceId, appId, config, linkService, flowObjService); } public PolicyGroupIdentifier createPolicyGroupChain(String id, @@ -111,15 +105,16 @@ public class PolicyGroupHandler extends DefaultGroupHandler { .setEthSrc(nodeMacAddr) .pushMpls() .setMpls(MplsLabel.mplsLabel(label)); - outBuckets.add(DefaultGroupBucket. + /*outBuckets.add(DefaultGroupBucket. createSelectGroupBucket(tBuilder.build())); GroupDescription desc = new DefaultGroupDescription(deviceId, GroupDescription.Type.INDIRECT, new GroupBuckets(outBuckets)); - //TODO: BoS + //TODO: BoS*/ previousGroupkey = key; - groupService.addGroup(desc); + //groupService.addGroup(desc); + //TODO: Use nextObjective APIs here } else { // Intermediate Groups GroupBucketIdentifier bucketId = @@ -179,20 +174,22 @@ public class PolicyGroupHandler extends DefaultGroupHandler { .setMpls(MplsLabel.mplsLabel(bucketId.label())); } //TODO: BoS - outBuckets.add(DefaultGroupBucket. - createSelectGroupBucket(tBuilder.build())); + /*outBuckets.add(DefaultGroupBucket. + createSelectGroupBucket(tBuilder.build()));*/ } - GroupDescription desc = new + /*GroupDescription desc = new DefaultGroupDescription(deviceId, GroupDescription.Type.SELECT, new GroupBuckets(outBuckets)); - groupService.addGroup(desc); + groupService.addGroup(desc);*/ + //TODO: Use nextObjective APIs here } } return innermostGroupkey; } - @Override + //TODO: Use nextObjective APIs to handle the group chains + /*@Override protected void handleGroupEvent(GroupEvent event) { if (event.type() == GroupEvent.Type.GROUP_ADDED) { if (dependentGroups.get(event.subject().appCookie()) != null) { @@ -253,7 +250,7 @@ public class PolicyGroupHandler extends DefaultGroupHandler { } } } - } + }*/ public PolicyGroupIdentifier generatePolicyGroupKey(String id, List params) { @@ -343,9 +340,10 @@ public class PolicyGroupHandler extends DefaultGroupHandler { groupsToBeDeleted.add(bucketId.outGroup()); } } - groupService.removeGroup(deviceId, + /*groupService.removeGroup(deviceId, getGroupKey(innerMostGroupKey), - appId); + appId);*/ + //TODO: Use nextObjective APIs here it.remove(); } } diff --git a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java index fbca078318..a551f798fd 100644 --- a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java +++ b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java @@ -356,10 +356,14 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { @Override public TrafficTreatment build() { - if (deferred.size() == 0 && immediate.size() == 0 - && table == null && !clear) { - drop(); - } + //Don't add DROP instruction by default when instruction + //set is empty. This will be handled in DefaultSingleTablePipeline + //driver. + + //if (deferred.size() == 0 && immediate.size() == 0 + // && table == null && !clear) { + // drop(); + //} return new DefaultTrafficTreatment(deferred, immediate, table, clear); } diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/DefaultSingleTablePipeline.java b/drivers/src/main/java/org/onosproject/driver/pipeline/DefaultSingleTablePipeline.java index 7308898040..9a091f4050 100644 --- a/drivers/src/main/java/org/onosproject/driver/pipeline/DefaultSingleTablePipeline.java +++ b/drivers/src/main/java/org/onosproject/driver/pipeline/DefaultSingleTablePipeline.java @@ -16,6 +16,7 @@ package org.onosproject.driver.pipeline; import com.google.common.util.concurrent.SettableFuture; + import org.onlab.osgi.ServiceDirectory; import org.onosproject.core.DefaultGroupId; import org.onosproject.net.DeviceId; @@ -23,11 +24,14 @@ import org.onosproject.net.behaviour.Pipeliner; import org.onosproject.net.behaviour.PipelinerContext; import org.onosproject.net.driver.AbstractHandlerBehaviour; import org.onosproject.net.flow.DefaultFlowRule; +import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.FlowRuleOperations; import org.onosproject.net.flow.FlowRuleOperationsContext; import org.onosproject.net.flow.FlowRuleService; import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.flowobjective.FilteringObjective; import org.onosproject.net.flowobjective.ForwardingObjective; import org.onosproject.net.flowobjective.NextObjective; @@ -70,9 +74,18 @@ public class DefaultSingleTablePipeline extends AbstractHandlerBehaviour impleme } TrafficSelector selector = fwd.selector(); + TrafficTreatment treatment = fwd.treatment(); + if ((fwd.treatment().deferred().size() == 0) && + (fwd.treatment().immediate().size() == 0) && + (fwd.treatment().tableTransition() == null) && + (!fwd.treatment().clearedDeferred())) { + TrafficTreatment.Builder flowTreatment = DefaultTrafficTreatment.builder(); + flowTreatment.add(Instructions.createDrop()); + treatment = flowTreatment.build(); + } FlowRule rule = new DefaultFlowRule(deviceId, selector, - fwd.treatment(), + treatment, fwd.priority(), fwd.appId(), new DefaultGroupId(fwd.id()), fwd.timeout(), fwd.permanent()); diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java new file mode 100644 index 0000000000..4e8d326e12 --- /dev/null +++ b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java @@ -0,0 +1,601 @@ +/* + * 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.driver.pipeline; + +import static org.onlab.util.Tools.groupedThreads; +import static org.slf4j.LoggerFactory.getLogger; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.RemovalCause; +import com.google.common.cache.RemovalNotification; + +import org.onlab.osgi.ServiceDirectory; +import org.onlab.packet.Ethernet; +import org.onlab.packet.VlanId; +import org.onlab.util.KryoNamespace; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.behaviour.NextGroup; +import org.onosproject.net.behaviour.Pipeliner; +import org.onosproject.net.behaviour.PipelinerContext; +import org.onosproject.net.driver.AbstractHandlerBehaviour; +import org.onosproject.net.flow.DefaultFlowRule; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.FlowRuleOperations; +import org.onosproject.net.flow.FlowRuleOperationsContext; +import org.onosproject.net.flow.FlowRuleService; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.criteria.Criteria; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.EthCriterion; +import org.onosproject.net.flow.criteria.EthTypeCriterion; +import org.onosproject.net.flow.criteria.IPCriterion; +import org.onosproject.net.flow.criteria.MplsCriterion; +import org.onosproject.net.flow.criteria.PortCriterion; +import org.onosproject.net.flow.criteria.VlanIdCriterion; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flowobjective.FilteringObjective; +import org.onosproject.net.flowobjective.FlowObjectiveStore; +import org.onosproject.net.flowobjective.ForwardingObjective; +import org.onosproject.net.flowobjective.NextObjective; +import org.onosproject.net.flowobjective.Objective; +import org.onosproject.net.flowobjective.ObjectiveError; +import org.onosproject.net.group.DefaultGroupBucket; +import org.onosproject.net.group.DefaultGroupDescription; +import org.onosproject.net.group.DefaultGroupKey; +import org.onosproject.net.group.Group; +import org.onosproject.net.group.GroupBucket; +import org.onosproject.net.group.GroupBuckets; +import org.onosproject.net.group.GroupDescription; +import org.onosproject.net.group.GroupEvent; +import org.onosproject.net.group.GroupKey; +import org.onosproject.net.group.GroupListener; +import org.onosproject.net.group.GroupService; +import org.slf4j.Logger; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * Driver for SPRING-OPEN pipeline. + */ +public class SpringOpenTTP extends AbstractHandlerBehaviour + implements Pipeliner { + + // Default table ID - compatible with CpqD switch + private static final int TABLE_VLAN = 0; + private static final int TABLE_TMAC = 1; + private static final int TABLE_IPV4_UNICAST = 2; + private static final int TABLE_MPLS = 3; + private static final int TABLE_ACL = 5; + + /** + * Set the default values. These variables will get overwritten based on the + * switch vendor type + */ + protected int vlanTableId = TABLE_VLAN; + protected int tmacTableId = TABLE_TMAC; + protected int ipv4UnicastTableId = TABLE_IPV4_UNICAST; + protected int mplsTableId = TABLE_MPLS; + protected int aclTableId = TABLE_ACL; + + protected final Logger log = getLogger(getClass()); + + private ServiceDirectory serviceDirectory; + private FlowRuleService flowRuleService; + private CoreService coreService; + protected GroupService groupService; + protected FlowObjectiveStore flowObjectiveStore; + protected DeviceId deviceId; + private ApplicationId appId; + + private Cache pendingGroups; + + private ScheduledExecutorService groupChecker = Executors + .newScheduledThreadPool(2, + groupedThreads("onos/pipeliner", + "spring-open-%d")); + protected KryoNamespace appKryo = new KryoNamespace.Builder() + .register(GroupKey.class).register(DefaultGroupKey.class) + .register(SegmentRoutingGroup.class).register(byte[].class).build(); + + @Override + public void init(DeviceId deviceId, PipelinerContext context) { + this.serviceDirectory = context.directory(); + this.deviceId = deviceId; + + pendingGroups = CacheBuilder + .newBuilder() + .expireAfterWrite(20, TimeUnit.SECONDS) + .removalListener((RemovalNotification notification) -> { + if (notification.getCause() == RemovalCause.EXPIRED) { + fail(notification.getValue(), + ObjectiveError.GROUPINSTALLATIONFAILED); + } + }).build(); + + groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, + TimeUnit.MILLISECONDS); + + coreService = serviceDirectory.get(CoreService.class); + flowRuleService = serviceDirectory.get(FlowRuleService.class); + groupService = serviceDirectory.get(GroupService.class); + flowObjectiveStore = context.store(); + + groupService.addListener(new InnerGroupListener()); + + appId = coreService + .registerApplication("org.onosproject.driver.SpringOpenTTP"); + + setTableMissEntries(); + log.info("Spring Open TTP driver initialized"); + } + + @Override + public void filter(FilteringObjective filteringObjective) { + if (filteringObjective.type() == FilteringObjective.Type.PERMIT) { + log.debug("processing PERMIT filter objective"); + processFilter(filteringObjective, + filteringObjective.op() == Objective.Operation.ADD, + filteringObjective.appId()); + } else { + log.debug("filter objective other than PERMIT not supported"); + fail(filteringObjective, ObjectiveError.UNSUPPORTED); + } + } + + @Override + public void forward(ForwardingObjective fwd) { + Collection rules; + FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder(); + + rules = processForward(fwd); + switch (fwd.op()) { + case ADD: + rules.stream().filter(rule -> rule != null) + .forEach(flowBuilder::add); + break; + case REMOVE: + rules.stream().filter(rule -> rule != null) + .forEach(flowBuilder::remove); + break; + default: + fail(fwd, ObjectiveError.UNKNOWN); + log.warn("Unknown forwarding type {}", fwd.op()); + } + + flowRuleService.apply(flowBuilder + .build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + pass(fwd); + } + + @Override + public void onError(FlowRuleOperations ops) { + fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); + } + })); + + } + + @Override + public void next(NextObjective nextObjective) { + switch (nextObjective.type()) { + case SIMPLE: + log.debug("processing SIMPLE next objective"); + Collection treatments = nextObjective.next(); + if (treatments.size() == 1) { + TrafficTreatment treatment = treatments.iterator().next(); + GroupBucket bucket = DefaultGroupBucket + .createIndirectGroupBucket(treatment); + final GroupKey key = new DefaultGroupKey( + appKryo.serialize(nextObjective + .id())); + GroupDescription groupDescription = new DefaultGroupDescription( + deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets( + Collections.singletonList(bucket)), + key, + nextObjective.appId()); + groupService.addGroup(groupDescription); + pendingGroups.put(key, nextObjective); + } + break; + case HASHED: + log.debug("processing HASHED next objective"); + List buckets = nextObjective + .next() + .stream() + .map((treatment) -> DefaultGroupBucket + .createSelectGroupBucket(treatment)) + .collect(Collectors.toList()); + if (!buckets.isEmpty()) { + final GroupKey key = new DefaultGroupKey( + appKryo.serialize(nextObjective + .id())); + GroupDescription groupDescription = new DefaultGroupDescription( + deviceId, + GroupDescription.Type.SELECT, + new GroupBuckets(buckets), + key, + nextObjective.appId()); + groupService.addGroup(groupDescription); + pendingGroups.put(key, nextObjective); + } + break; + case BROADCAST: + case FAILOVER: + log.debug("BROADCAST and FAILOVER next objectives not supported"); + fail(nextObjective, ObjectiveError.UNSUPPORTED); + log.warn("Unsupported next objective type {}", nextObjective.type()); + break; + default: + fail(nextObjective, ObjectiveError.UNKNOWN); + log.warn("Unknown next objective type {}", nextObjective.type()); + } + + } + + private Collection processForward(ForwardingObjective fwd) { + switch (fwd.flag()) { + case SPECIFIC: + return processSpecific(fwd); + case VERSATILE: + return processVersatile(fwd); + default: + fail(fwd, ObjectiveError.UNKNOWN); + log.warn("Unknown forwarding flag {}", fwd.flag()); + } + return Collections.emptySet(); + } + + private Collection processVersatile(ForwardingObjective fwd) { + fail(fwd, ObjectiveError.UNSUPPORTED); + return Collections.emptySet(); + } + + protected Collection processSpecific(ForwardingObjective fwd) { + log.debug("Processing specific"); + TrafficSelector selector = fwd.selector(); + EthTypeCriterion ethType = (EthTypeCriterion) selector + .getCriterion(Criterion.Type.ETH_TYPE); + if ((ethType == null) || + ((((short) ethType.ethType()) != Ethernet.TYPE_IPV4) && + (((short) ethType.ethType()) != Ethernet.MPLS_UNICAST))) { + log.debug("processSpecific: Unsupported " + + "forwarding objective criteraia"); + fail(fwd, ObjectiveError.UNSUPPORTED); + return Collections.emptySet(); + } + + TrafficSelector.Builder filteredSelectorBuilder = + DefaultTrafficSelector.builder(); + int forTableId = -1; + if (((short) ethType.ethType()) == Ethernet.TYPE_IPV4) { + filteredSelectorBuilder = filteredSelectorBuilder + .matchEthType(Ethernet.TYPE_IPV4) + .matchIPDst(((IPCriterion) selector + .getCriterion(Criterion.Type.IPV4_DST)) + .ip()); + forTableId = ipv4UnicastTableId; + log.debug("processing IPv4 specific forwarding objective"); + } else { + filteredSelectorBuilder = filteredSelectorBuilder + .matchEthType(Ethernet.MPLS_UNICAST) + .matchMplsLabel(((MplsCriterion) + selector.getCriterion(Criterion.Type.MPLS_LABEL)).label()); + //TODO: Add Match for BoS + //if (selector.getCriterion(Criterion.Type.MPLS_BOS) != null) { + //} + forTableId = mplsTableId; + log.debug("processing MPLS specific forwarding objective"); + } + + TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment + .builder(); + if (fwd.treatment() != null) { + for (Instruction i : fwd.treatment().allInstructions()) { + treatmentBuilder.add(i); + } + } + + //TODO: Analyze the forwarding objective here to make + //device specific decision such as no ECMP groups in Dell + //switches. + if (fwd.nextId() != null) { + NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); + + if (next != null) { + GroupKey key = appKryo.deserialize(next.data()); + + Group group = groupService.getGroup(deviceId, key); + + if (group == null) { + log.warn("The group left!"); + fail(fwd, ObjectiveError.GROUPMISSING); + return Collections.emptySet(); + } + treatmentBuilder.group(group.id()); + log.debug("Adding OUTGROUP action"); + } + } + + TrafficSelector filteredSelector = filteredSelectorBuilder.build(); + TrafficTreatment treatment = treatmentBuilder.transition(aclTableId) + .build(); + + FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() + .fromApp(fwd.appId()).withPriority(fwd.priority()) + .forDevice(deviceId).withSelector(filteredSelector) + .withTreatment(treatment); + + if (fwd.permanent()) { + ruleBuilder.makePermanent(); + } else { + ruleBuilder.makeTemporary(fwd.timeout()); + } + + ruleBuilder.forTable(forTableId); + return Collections.singletonList(ruleBuilder.build()); + + } + + protected List processEthDstFilter(Criterion c, + FilteringObjective filt, + ApplicationId applicationId) { + List rules = new ArrayList(); + EthCriterion e = (EthCriterion) c; + TrafficSelector.Builder selectorIp = DefaultTrafficSelector + .builder(); + TrafficTreatment.Builder treatmentIp = DefaultTrafficTreatment + .builder(); + 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; + } + + 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 { + log.warn("No key defined in filtering objective from app: {}. Not" + + "processing filtering objective", applicationId); + fail(filt, ObjectiveError.UNKNOWN); + return; + } + // convert filtering conditions for switch-intfs into flowrules + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + for (Criterion c : filt.conditions()) { + if (c.type() == Criterion.Type.ETH_DST) { + for (FlowRule rule : processEthDstFilter(c, + filt, + applicationId)) { + 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(); + } + 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()); + TrafficSelector.Builder selector = DefaultTrafficSelector + .builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment + .builder(); + selector.matchEthType(Ethernet.TYPE_IPV4); + selector.matchIPDst(ip.ip()); + treatment.transition(aclTableId); + FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(filt.priority()).fromApp(applicationId) + .makePermanent().forTable(ipv4UnicastTableId).build(); + ops = install ? ops.add(rule) : ops.remove(rule); + } else { + log.warn("Driver does not currently process filtering condition" + + " of type: {}", c.type()); + fail(filt, ObjectiveError.UNSUPPORTED); + } + } + // apply filtering flow rules + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + pass(filt); + log.info("Provisioned tables for segment router"); + } + + @Override + public void onError(FlowRuleOperations ops) { + fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED); + log.info("Failed to provision tables for segment router"); + } + })); + } + + protected void setTableMissEntries() { + // set all table-miss-entries + populateTableMissEntry(vlanTableId, true, false, false, -1); + populateTableMissEntry(tmacTableId, true, false, false, -1); + populateTableMissEntry(ipv4UnicastTableId, false, true, true, + aclTableId); + populateTableMissEntry(mplsTableId, false, true, true, aclTableId); + populateTableMissEntry(aclTableId, false, false, false, -1); + } + + protected void populateTableMissEntry(int tableToAdd, + boolean toControllerNow, + boolean toControllerWrite, + boolean toTable, int tableToSend) { + TrafficSelector selector = DefaultTrafficSelector.builder().build(); + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + + if (toControllerNow) { + tBuilder.setOutput(PortNumber.CONTROLLER); + } + + if (toControllerWrite) { + tBuilder.deferred().setOutput(PortNumber.CONTROLLER); + } + + if (toTable) { + tBuilder.transition(tableToSend); + } + + FlowRule flow = DefaultFlowRule.builder().forDevice(deviceId) + .withSelector(selector).withTreatment(tBuilder.build()) + .withPriority(0).fromApp(appId).makePermanent() + .forTable(tableToAdd).build(); + + flowRuleService.applyFlowRules(flow); + } + + private void pass(Objective obj) { + if (obj.context().isPresent()) { + obj.context().get().onSuccess(obj); + } + } + + protected void fail(Objective obj, ObjectiveError error) { + if (obj.context().isPresent()) { + obj.context().get().onError(obj, error); + } + } + + private class InnerGroupListener implements GroupListener { + @Override + public void event(GroupEvent event) { + if (event.type() == GroupEvent.Type.GROUP_ADDED) { + GroupKey key = event.subject().appCookie(); + + NextObjective obj = pendingGroups.getIfPresent(key); + if (obj != null) { + flowObjectiveStore + .putNextGroup(obj.id(), + new SegmentRoutingGroup(key)); + pass(obj); + pendingGroups.invalidate(key); + } + } + } + } + + private class GroupChecker implements Runnable { + + @Override + public void run() { + Set keys = pendingGroups + .asMap() + .keySet() + .stream() + .filter(key -> groupService.getGroup(deviceId, key) != null) + .collect(Collectors.toSet()); + + keys.stream() + .forEach(key -> { + NextObjective obj = pendingGroups + .getIfPresent(key); + if (obj == null) { + return; + } + pass(obj); + pendingGroups.invalidate(key); + flowObjectiveStore.putNextGroup(obj.id(), + new SegmentRoutingGroup( + key)); + }); + } + } + + private class SegmentRoutingGroup implements NextGroup { + + private final GroupKey key; + + public SegmentRoutingGroup(GroupKey key) { + this.key = key; + } + + public GroupKey key() { + return key; + } + + @Override + public byte[] data() { + return appKryo.serialize(key); + } + + } +} diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java new file mode 100644 index 0000000000..4a817bf33e --- /dev/null +++ b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java @@ -0,0 +1,217 @@ +/* + * 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.driver.pipeline; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.onlab.packet.Ethernet; +import org.onlab.packet.MacAddress; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.behaviour.NextGroup; +import org.onosproject.net.flow.DefaultFlowRule; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.EthCriterion; +import org.onosproject.net.flow.criteria.EthTypeCriterion; +import org.onosproject.net.flow.criteria.IPCriterion; +import org.onosproject.net.flow.criteria.MplsCriterion; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flowobjective.FilteringObjective; +import org.onosproject.net.flowobjective.ForwardingObjective; +import org.onosproject.net.flowobjective.ObjectiveError; +import org.onosproject.net.group.Group; +import org.onosproject.net.group.GroupKey; + +/** + * Spring-open driver implementation for Dell hardware switches. + */ +public class SpringOpenTTPDell extends SpringOpenTTP { + + /* Table IDs to be used for Dell Open Segment Routers*/ + private static final int DELL_TABLE_VLAN = 17; + private static final int DELL_TABLE_TMAC = 18; + private static final int DELL_TABLE_IPV4_UNICAST = 30; + private static final int DELL_TABLE_MPLS = 25; + private static final int DELL_TABLE_ACL = 40; + + //TODO: Store this info in the distributed store. + private MacAddress deviceTMac = null; + + public SpringOpenTTPDell() { + super(); + vlanTableId = DELL_TABLE_VLAN; + tmacTableId = DELL_TABLE_TMAC; + ipv4UnicastTableId = DELL_TABLE_IPV4_UNICAST; + mplsTableId = DELL_TABLE_MPLS; + aclTableId = DELL_TABLE_ACL; + } + + @Override + protected void setTableMissEntries() { + // No need to set table-miss-entries in Dell switches + return; + } + + @Override + //Dell switches need ETH_DST based match condition in all IP table entries. + //So this method overrides the default spring-open behavior and adds + //ETH_DST match condition while pushing IP table flow rules + protected Collection processSpecific(ForwardingObjective fwd) { + log.debug("Processing specific"); + TrafficSelector selector = fwd.selector(); + EthTypeCriterion ethType = (EthTypeCriterion) selector + .getCriterion(Criterion.Type.ETH_TYPE); + if ((ethType == null) || + ((((short) ethType.ethType()) != Ethernet.TYPE_IPV4) && + (((short) ethType.ethType()) != Ethernet.MPLS_UNICAST))) { + log.debug("processSpecific: Unsupported " + + "forwarding objective criteraia"); + fail(fwd, ObjectiveError.UNSUPPORTED); + return Collections.emptySet(); + } + + TrafficSelector.Builder filteredSelectorBuilder = + DefaultTrafficSelector.builder(); + int forTableId = -1; + if (((short) ethType.ethType()) == Ethernet.TYPE_IPV4) { + if (deviceTMac == null) { + log.debug("processSpecific: ETH_DST filtering " + + "objective is not set which is required " + + "before sending a IPv4 forwarding objective"); + //TODO: Map the error to more appropriate error code. + fail(fwd, ObjectiveError.DEVICEMISSING); + return Collections.emptySet(); + } + filteredSelectorBuilder = filteredSelectorBuilder + .matchEthType(Ethernet.TYPE_IPV4) + .matchEthDst(deviceTMac) + .matchIPDst(((IPCriterion) selector + .getCriterion(Criterion.Type.IPV4_DST)) + .ip()); + forTableId = ipv4UnicastTableId; + log.debug("processing IPv4 specific forwarding objective"); + } else { + filteredSelectorBuilder = filteredSelectorBuilder + .matchEthType(Ethernet.MPLS_UNICAST) + .matchMplsLabel(((MplsCriterion) + selector.getCriterion(Criterion.Type.MPLS_LABEL)).label()); + //TODO: Add Match for BoS + //if (selector.getCriterion(Criterion.Type.MPLS_BOS) != null) { + //} + forTableId = mplsTableId; + log.debug("processing MPLS specific forwarding objective"); + } + + TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment + .builder(); + if (fwd.treatment() != null) { + for (Instruction i : fwd.treatment().allInstructions()) { + treatmentBuilder.add(i); + } + } + + if (fwd.nextId() != null) { + NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); + + if (next != null) { + GroupKey key = appKryo.deserialize(next.data()); + + Group group = groupService.getGroup(deviceId, key); + + if (group == null) { + log.warn("The group left!"); + fail(fwd, ObjectiveError.GROUPMISSING); + return Collections.emptySet(); + } + treatmentBuilder.group(group.id()); + log.debug("Adding OUTGROUP action"); + } + } + + TrafficSelector filteredSelector = filteredSelectorBuilder.build(); + TrafficTreatment treatment = treatmentBuilder.transition(aclTableId) + .build(); + + FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() + .fromApp(fwd.appId()).withPriority(fwd.priority()) + .forDevice(deviceId).withSelector(filteredSelector) + .withTreatment(treatment); + + if (fwd.permanent()) { + ruleBuilder.makePermanent(); + } else { + ruleBuilder.makeTemporary(fwd.timeout()); + } + + ruleBuilder.forTable(forTableId); + return Collections.singletonList(ruleBuilder.build()); + + } + + @Override + //Dell switches need ETH_DST based match condition in all IP table entries. + //So while processing the ETH_DST based filtering objective, store + //the device MAC to be used locally to use it while pushing the IP rules. + protected List processEthDstFilter(Criterion c, + FilteringObjective filt, + ApplicationId applicationId) { + List rules = new ArrayList(); + 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 + 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; + } + +} \ No newline at end of file diff --git a/drivers/src/main/resources/onos-drivers.xml b/drivers/src/main/resources/onos-drivers.xml index 2efc6079c1..d7c61c8f38 100644 --- a/drivers/src/main/resources/onos-drivers.xml +++ b/drivers/src/main/resources/onos-drivers.xml @@ -23,4 +23,12 @@ - \ No newline at end of file + + + + + + + diff --git a/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java b/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java index d47c78f27e..ebfa635a9c 100644 --- a/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java +++ b/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java @@ -19,10 +19,11 @@ package org.onosproject.openflow.controller.driver; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; import org.jboss.netty.channel.Channel; import org.onlab.packet.IpAddress; @@ -64,7 +65,7 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver { private OFVersion ofVersion; - protected OFPortDescStatsReply ports; + protected List ports = new ArrayList<>(); protected boolean tableFull; @@ -251,7 +252,12 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver { @Override public void setPortDescReply(OFPortDescStatsReply portDescReply) { - this.ports = portDescReply; + this.ports.add(portDescReply); + } + + @Override + public void setPortDescReplies(List portDescReplies) { + this.ports.addAll(portDescReplies); } @Override @@ -379,7 +385,10 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver { @Override public List getPorts() { - return Collections.unmodifiableList(ports.getEntries()); + return this.ports.stream() + .flatMap((portReply) -> (portReply.getEntries().stream())) + .collect(Collectors.toList()); + //return Collections.unmodifiableList(ports.getEntries()); } @Override diff --git a/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/OpenFlowSwitchDriver.java b/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/OpenFlowSwitchDriver.java index c6f83e2dbe..a83b608b98 100644 --- a/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/OpenFlowSwitchDriver.java +++ b/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/OpenFlowSwitchDriver.java @@ -136,6 +136,12 @@ public interface OpenFlowSwitchDriver extends OpenFlowSwitch { */ public void setPortDescReply(OFPortDescStatsReply portDescReply); + /** + * Sets the ports on this switch. + * @param portDescReplies list of port set and descriptions + */ + public void setPortDescReplies(List portDescReplies); + /** * Sets the features reply for this switch. * @param featuresReply the features to set. diff --git a/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java b/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java index d95bb1d2f0..4779c5dd0a 100644 --- a/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java +++ b/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java @@ -97,7 +97,8 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { // Temporary storage for switch-features and port-description private OFFeaturesReply featuresReply; - private OFPortDescStatsReply portDescReply; + private List portDescReplies; + //private OFPortDescStatsReply portDescReply; // a concurrent ArrayList to temporarily store port status messages // before we are ready to deal with them private final CopyOnWriteArrayList pendingPortStatusMsg; @@ -121,6 +122,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { this.controller = controller; this.state = ChannelState.INIT; this.pendingPortStatusMsg = new CopyOnWriteArrayList(); + this.portDescReplies = new ArrayList(); factory13 = controller.getOFMessageFactory13(); factory10 = controller.getOFMessageFactory10(); duplicateDpidFound = Boolean.FALSE; @@ -294,10 +296,15 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { } if (m.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) { log.warn("Stats reply indicates more stats from sw {} for " - + "port description - not currently handled", + + "port description", h.getSwitchInfoString()); + h.portDescReplies.add((OFPortDescStatsReply)m); + return; } - h.portDescReply = (OFPortDescStatsReply) m; // temp store + else { + h.portDescReplies.add((OFPortDescStatsReply)m); + } + //h.portDescReply = (OFPortDescStatsReply) m; // temp store log.info("Received port desc reply for switch at {}", h.getSwitchInfoString()); try { @@ -418,7 +425,8 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { h.sw.setOFVersion(h.ofVersion); h.sw.setFeaturesReply(h.featuresReply); - h.sw.setPortDescReply(h.portDescReply); + //h.sw.setPortDescReply(h.portDescReply); + h.sw.setPortDescReplies(h.portDescReplies); h.sw.setConnected(true); h.sw.setChannel(h.channel); // boolean success = h.sw.connectSwitch(); diff --git a/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/RoleManagerTest.java b/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/RoleManagerTest.java index 5a74e9a0f3..fb0e4060f4 100644 --- a/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/RoleManagerTest.java +++ b/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/RoleManagerTest.java @@ -254,6 +254,10 @@ public class RoleManagerTest { public void setPortDescReply(OFPortDescStatsReply portDescReply) { } + @Override + public void setPortDescReplies(List portDescReplies) { + } + @Override public void setFeaturesReply(OFFeaturesReply featuresReply) { } diff --git a/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/DriverManager.java b/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/DriverManager.java index 746cdd587e..c10c3a9b9a 100644 --- a/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/DriverManager.java +++ b/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/DriverManager.java @@ -32,6 +32,7 @@ import org.slf4j.LoggerFactory; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; /** * A simple implementation of a driver manager that differentiates between @@ -73,6 +74,14 @@ public final class DriverManager implements OpenFlowSwitchDriverFactory { return new OFSwitchImplSpringOpenTTP(dpid, desc); } + //TODO: Temporary work around until the configuration based + // driver manager framework is ready + if (vendor.contains("Dell") + && + hw.contains("OpenFlow switch HW ver. 1.0")) { + return new OFSwitchImplSpringOpenTTPDellOSR(dpid, desc); + } + if (hw.startsWith("Open vSwitch")) { if (ofv == OFVersion.OF_10) { return new OFSwitchImplOVS10(dpid, desc); @@ -140,7 +149,9 @@ public final class DriverManager implements OpenFlowSwitchDriverFactory { if (this.factory().getVersion() == OFVersion.OF_10) { return Collections.unmodifiableList(features.getPorts()); } else { - return Collections.unmodifiableList(ports.getEntries()); + return Collections.unmodifiableList(this.ports.stream() + .flatMap((portReply) -> (portReply.getEntries().stream())) + .collect(Collectors.toList())); } } diff --git a/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFOpticalSwitchImplLINC13.java b/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFOpticalSwitchImplLINC13.java index 61c37df545..37022a129d 100644 --- a/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFOpticalSwitchImplLINC13.java +++ b/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFOpticalSwitchImplLINC13.java @@ -183,7 +183,7 @@ public class OFOpticalSwitchImplLINC13 extends AbstractOpenFlowSwitch { @Override public List getPorts() { List portEntries = new ArrayList<>(); - portEntries.addAll(ports.getEntries()); + portEntries.addAll(super.getPorts()); if (wPorts != null) { portEntries.addAll(wPorts.getEntries()); } diff --git a/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFSwitchImplSpringOpenTTP.java b/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFSwitchImplSpringOpenTTP.java index 4e7f61d5c5..80fc95f316 100644 --- a/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFSwitchImplSpringOpenTTP.java +++ b/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFSwitchImplSpringOpenTTP.java @@ -34,6 +34,8 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +//TODO: Knock-off this class as we don't need any switch/app specific +//drivers in the south bound layers. public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { private OFFactory factory; @@ -48,8 +50,9 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { private static final int TABLE_MPLS = 3; private static final int TABLE_ACL = 5; - /* Set the default values. These variables will get - * overwritten based on the switch vendor type + /* + * Set the default values. These variables will get overwritten based on the + * switch vendor type */ protected int vlanTableId = TABLE_VLAN; protected int tmacTableId = TABLE_TMAC; @@ -64,13 +67,13 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { setSwitchDescription(desc); } - @Override public String toString() { - return "OFSwitchImplSpringOpenTTP [" + ((channel != null) - ? channel.getRemoteAddress() : "?") - + " DPID[" + ((this.getStringId() != null) ? - this.getStringId() : "?") + "]]"; + return "OFSwitchImplSpringOpenTTP [" + + ((channel != null) ? channel.getRemoteAddress() : "?") + + " DPID[" + + ((this.getStringId() != null) ? this.getStringId() : "?") + + "]]"; } @Override @@ -78,7 +81,6 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { return null; } - @Override public void startDriverHandshake() { log.debug("Starting driver handshake for sw {}", getStringId()); @@ -101,8 +103,6 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { return driverHandshakeComplete.get(); } - - @Override public void processDriverHandshakeMessage(OFMessage m) { if (!startDriverHandshakeCalled) { @@ -113,15 +113,14 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { } } - @Override public void write(OFMessage msg) { - this.channel.write(Collections.singletonList(msg)); + channel.write(Collections.singletonList(msg)); } @Override public void write(List msgs) { - this.channel.write(msgs); + channel.write(msgs); } @Override @@ -134,10 +133,10 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { for (OFInstruction i : instructions) { if (i instanceof OFInstructionGotoTable) { OFInstructionGotoTable gotoTable = (OFInstructionGotoTable) i; - TableType tid = TableType.values()[gotoTable.getTableId().getValue()]; - newInstructions.add( - gotoTable.createBuilder() - .setTableId(getTableId(tid)).build()); + TableType tid = TableType.values()[gotoTable.getTableId() + .getValue()]; + newInstructions.add(gotoTable.createBuilder() + .setTableId(getTableId(tid)).build()); } else { newInstructions.add(i); } @@ -156,38 +155,39 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { @Override public TableType getTableType(TableId tid) { switch (tid.getValue()) { - case TABLE_IPV4_UNICAST: - return TableType.IP; - case TABLE_MPLS: - return TableType.MPLS; - case TABLE_ACL: - return TableType.ACL; - case TABLE_VLAN: - return TableType.VLAN; - case TABLE_TMAC: - return TableType.ETHER; - default: - log.error("Table type for Table id {} is not supported in the driver", tid); - return TableType.NONE; + case TABLE_IPV4_UNICAST: + return TableType.IP; + case TABLE_MPLS: + return TableType.MPLS; + case TABLE_ACL: + return TableType.ACL; + case TABLE_VLAN: + return TableType.VLAN; + case TABLE_TMAC: + return TableType.ETHER; + default: + log.error("Table type for Table id {} is not supported in the driver", + tid); + return TableType.NONE; } } private TableId getTableId(TableType tableType) { switch (tableType) { - case IP: - return TableId.of(ipv4UnicastTableId); - case MPLS: - return TableId.of(mplsTableId); - case ACL: - return TableId.of(aclTableId); - case VLAN: - return TableId.of(vlanTableId); - case ETHER: - return TableId.of(tmacTableId); - default: { - log.error("Table type {} is not supported in the driver", tableType); - return TableId.NONE; - } + case IP: + return TableId.of(ipv4UnicastTableId); + case MPLS: + return TableId.of(mplsTableId); + case ACL: + return TableId.of(aclTableId); + case VLAN: + return TableId.of(vlanTableId); + case ETHER: + return TableId.of(tmacTableId); + default: { + log.error("Table type {} is not supported in the driver", tableType); + return TableId.NONE; + } } } diff --git a/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFSwitchImplSpringOpenTTPDellOSR.java b/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFSwitchImplSpringOpenTTPDellOSR.java new file mode 100644 index 0000000000..783a37e643 --- /dev/null +++ b/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFSwitchImplSpringOpenTTPDellOSR.java @@ -0,0 +1,65 @@ +/* + * 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.openflow.drivers; + +import org.onosproject.openflow.controller.Dpid; +import org.projectfloodlight.openflow.protocol.OFDescStatsReply; +import org.projectfloodlight.openflow.types.TableId; + +/** + * OFDescriptionStatistics Vendor (Manufacturer Desc.): Dell Make (Hardware + * Desc.) : OpenFlow 1.3 Reference Userspace Switch Model (Datapath Desc.) : + * None Software : Serial : None. + */ +//TODO: Knock-off this class as we don't need any switch/app specific +//drivers in the south bound layers. +public class OFSwitchImplSpringOpenTTPDellOSR extends OFSwitchImplSpringOpenTTP { + + /* Table IDs to be used for Dell Open Segment Routers*/ + private static final int DELL_TABLE_VLAN = 17; + private static final int DELL_TABLE_TMAC = 18; + private static final int DELL_TABLE_IPV4_UNICAST = 30; + private static final int DELL_TABLE_MPLS = 25; + private static final int DELL_TABLE_ACL = 40; + + public OFSwitchImplSpringOpenTTPDellOSR(Dpid dpid, OFDescStatsReply desc) { + super(dpid, desc); + vlanTableId = DELL_TABLE_VLAN; + tmacTableId = DELL_TABLE_TMAC; + ipv4UnicastTableId = DELL_TABLE_IPV4_UNICAST; + mplsTableId = DELL_TABLE_MPLS; + aclTableId = DELL_TABLE_ACL; + } + + @Override + public TableType getTableType(TableId tid) { + switch (tid.getValue()) { + case DELL_TABLE_IPV4_UNICAST: + return TableType.IP; + case DELL_TABLE_MPLS: + return TableType.MPLS; + case DELL_TABLE_ACL: + return TableType.ACL; + case DELL_TABLE_VLAN: + return TableType.VLAN; + case DELL_TABLE_TMAC: + return TableType.ETHER; + default: + log.error("Table type for Table id {} is not supported in the driver", tid); + return TableType.NONE; + } + } +} \ No newline at end of file diff --git a/tools/package/config/samples/segmentrouting_dell.conf b/tools/package/config/samples/segmentrouting_dell.conf new file mode 100644 index 0000000000..be489a65f0 --- /dev/null +++ b/tools/package/config/samples/segmentrouting_dell.conf @@ -0,0 +1,93 @@ +{ + "comment": " Multilayer topology description and configuration", + "restrictSwitches": true, + "restrictLinks": true, + + "switchConfig": + [ + { "nodeDpid" : "of:00010001e88b9368", "name": "Dell-R1", "type": "Router_SR", "allowed": true, + "latitude": 80.80, "longitude": 90.10, + "params": { "routerIp": "192.168.0.1/32", + "routerMac": "00:01:e8:8b:93:6b", + "nodeSid": 101, + "isEdgeRouter" : true, + "subnets": [ + { "portNo": 46, "subnetIp": "10.200.1.1/24" } + ] + } + }, + + { "nodeDpid": "of:00010001e88b939b", "name": "Dell-R2", "type": "Router_SR", "allowed": true, + "latitude": 80.80, "longitude": 90.10, + "params": { "routerIp": "192.168.0.2/32", + "routerMac": "00:01:e8:8b:93:9e", + "nodeSid": 102, + "isEdgeRouter" : true, + "subnets": [ + { "portNo": 46, "subnetIp": "10.200.2.1/24" } + ] + } + }, + + { "nodeDpid": "of:00010001e88b938c", "name": "Dell-R3", "type": "Router_SR", "allowed": true, + "latitude": 80.80, "longitude": 90.10, + "params": { "routerIp": "192.168.0.3/32", + "routerMac": "00:01:e8:8b:93:8f", + "nodeSid": 103, + "isEdgeRouter" : true, + "subnets": [ + { "portNo": 46, "subnetIp": "10.200.3.1/24" } + ] + } + }, + + { "nodeDpid": "of:00010001e88b93ad", "name": "Dell-R4", "type": "Router_SR", "allowed": true, + "latitude": 80.80, "longitude": 90.10, + "params": { "routerIp": "192.168.0.4/32", + "routerMac": "00:01:e8:8b:93:b0", + "nodeSid": 104, + "isEdgeRouter" : true, + "subnets": [ + { "portNo": 46, "subnetIp": "10.200.4.1/24" } + ] + } + }, + + { "nodeDpid": "of:00010001e88b93bc", "name": "Dell-R5", "type": "Router_SR", "allowed": true, + "latitude": 80.80, "longitude": 90.10, + "params": { "routerIp": "192.168.0.5/32", + "routerMac": "00:01:e8:8b:93:bf", + "nodeSid": 105, + "isEdgeRouter" : false + } + }, + + { "nodeDpid": "of:00010001e88b93c2", "name": "Dell-R6", "type": "Router_SR", "allowed": true, + "latitude": 80.80, "longitude": 90.10, + "params": { "routerIp": "192.168.0.6/32", + "routerMac": "00:01:e8:8b:93:c5", + "nodeSid": 106, + "isEdgeRouter" : false + } + }, + + { "nodeDpid": "of:00010001e88b9398", "name": "Dell-R7", "type": "Router_SR", "allowed": true, + "latitude": 80.80, "longitude": 90.10, + "params": { "routerIp": "192.168.0.7/32", + "routerMac": "00:01:e8:8b:93:9b", + "nodeSid": 107, + "isEdgeRouter": false + } + }, + + { "nodeDpid": "of:00010001e88b27e3", "name": "Dell-R8", "type": "Router_SR", "allowed": true, + "latitude": 80.80, "longitude": 90.10, + "params": { "routerIp": "192.168.0.8/32", + "routerMac": "00:01:e8:8b:27:e6", + "nodeSid": 108, + "isEdgeRouter": false + } + } + + ] +}