summaryrefslogtreecommitdiffstats
path: root/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
diff options
context:
space:
mode:
authorAshlee Young <ashlee@onosfw.com>2015-09-09 22:15:21 -0700
committerAshlee Young <ashlee@onosfw.com>2015-09-09 22:15:21 -0700
commit13d05bc8458758ee39cb829098241e89616717ee (patch)
tree22a4d1ce65f15952f07a3df5af4b462b4697cb3a /framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
parent6139282e1e93c2322076de4b91b1c85d0bc4a8b3 (diff)
ONOS checkin based on commit tag e796610b1f721d02f9b0e213cf6f7790c10ecd60
Change-Id: Ife8810491034fe7becdba75dda20de4267bd15cd
Diffstat (limited to 'framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java')
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java430
1 files changed, 430 insertions, 0 deletions
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
new file mode 100644
index 00000000..59fc4ca7
--- /dev/null
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -0,0 +1,430 @@
+/*
+ * 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 org.onlab.packet.Ethernet;
+import org.onlab.packet.Ip4Address;
+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.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+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.Objective;
+import org.onosproject.net.flowobjective.ObjectiveError;
+import org.onosproject.net.flowobjective.ForwardingObjective.Builder;
+import org.onosproject.net.flowobjective.ObjectiveContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class RoutingRulePopulator {
+
+ private static final Logger log = LoggerFactory
+ .getLogger(RoutingRulePopulator.class);
+
+ private AtomicLong rulePopulationCounter;
+ private SegmentRoutingManager srManager;
+ private DeviceConfiguration config;
+ /**
+ * Creates a RoutingRulePopulator object.
+ *
+ * @param srManager segment routing manager reference
+ */
+ public RoutingRulePopulator(SegmentRoutingManager srManager) {
+ this.srManager = srManager;
+ this.config = checkNotNull(srManager.deviceConfiguration);
+ this.rulePopulationCounter = new AtomicLong(0);
+ }
+
+ /**
+ * Resets the population counter.
+ */
+ public void resetCounter() {
+ rulePopulationCounter.set(0);
+ }
+
+ /**
+ * Returns the number of rules populated.
+ *
+ * @return number of rules
+ */
+ public long getCounter() {
+ return rulePopulationCounter.get();
+ }
+
+ /**
+ * 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
+ * @param hostMac host MAC address
+ * @param outPort port where the host is connected
+ */
+ public void populateIpRuleForHost(DeviceId deviceId, Ip4Address hostIp,
+ MacAddress hostMac, PortNumber outPort) {
+ TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
+
+ sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, 32));
+ sbuilder.matchEthType(Ethernet.TYPE_IPV4);
+
+ tbuilder.deferred()
+ .setEthDst(hostMac)
+ .setEthSrc(config.getDeviceMac(deviceId))
+ .setOutput(outPort);
+
+ TrafficTreatment treatment = tbuilder.build();
+ TrafficSelector selector = sbuilder.build();
+
+ ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
+ .builder().fromApp(srManager.appId).makePermanent()
+ .withSelector(selector).withTreatment(treatment)
+ .withPriority(100).withFlag(ForwardingObjective.Flag.SPECIFIC);
+
+ log.debug("Installing IPv4 forwarding objective "
+ + "for host {} in switch {}", hostIp, deviceId);
+ srManager.flowObjectiveService.
+ forward(deviceId,
+ fwdBuilder.
+ add(new SRObjectiveContext(deviceId,
+ SRObjectiveContext.ObjectiveType.FORWARDING)));
+ rulePopulationCounter.incrementAndGet();
+ }
+
+ /**
+ * Populates IP flow rules for the subnets of the destination router.
+ *
+ * @param deviceId switch ID to set the rules
+ * @param subnets subnet information
+ * @param destSw destination switch ID
+ * @param nextHops next hop switch ID list
+ * @return true if all rules are set successfully, false otherwise
+ */
+ public boolean populateIpRuleForSubnet(DeviceId deviceId,
+ List<Ip4Prefix> subnets,
+ DeviceId destSw,
+ Set<DeviceId> nextHops) {
+
+ for (IpPrefix subnet : subnets) {
+ if (!populateIpRuleForRouter(deviceId, subnet, destSw, nextHops)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Populates IP flow rules for the router IP address.
+ *
+ * @param deviceId device ID to set the rules
+ * @param ipPrefix the IP address of the destination router
+ * @param destSw device ID of the destination router
+ * @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<DeviceId> nextHops) {
+
+ TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
+
+ sbuilder.matchIPDst(ipPrefix);
+ sbuilder.matchEthType(Ethernet.TYPE_IPV4);
+
+ NeighborSet ns = null;
+
+ // 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.deferred().decNwTtl();
+ ns = new NeighborSet(nextHops);
+ } else {
+ tbuilder.deferred().copyTtlOut();
+ ns = new NeighborSet(nextHops, config.getSegmentId(destSw));
+ }
+
+ TrafficTreatment treatment = tbuilder.build();
+ TrafficSelector selector = sbuilder.build();
+
+ if (srManager.getNextObjectiveId(deviceId, ns) <= 0) {
+ log.warn("No next objective in {} for ns: {}", deviceId, ns);
+ return false;
+ }
+
+ 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(new SRObjectiveContext(deviceId,
+ SRObjectiveContext.ObjectiveType.FORWARDING)));
+ rulePopulationCounter.incrementAndGet();
+
+ return true;
+ }
+
+ /**
+ * Populates MPLS flow rules to all transit routers.
+ *
+ * @param deviceId device ID of the switch to set the rules
+ * @param destSwId destination switch device ID
+ * @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<DeviceId> nextHops) {
+
+ TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
+ List<ForwardingObjective.Builder> fwdObjBuilders = new ArrayList<ForwardingObjective.Builder>();
+
+ // 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 (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
+ log.debug("populateMplsRule: Installing MPLS forwarding objective for "
+ + "label {} in switch {} with PHP",
+ config.getSegmentId(destSwId),
+ deviceId);
+
+ ForwardingObjective.Builder fwdObjBosBuilder =
+ getMplsForwardingObjective(deviceId,
+ destSwId,
+ 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 {
+ log.debug("Installing MPLS forwarding objective for "
+ + "label {} in switch {} without PHP",
+ config.getSegmentId(destSwId),
+ deviceId);
+
+ 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;
+ }
+ }
+
+ TrafficSelector selector = sbuilder.build();
+ for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) {
+ ((Builder) ((Builder) fwdObjBuilder.fromApp(srManager.appId)
+ .makePermanent()).withSelector(selector)
+ .withPriority(100))
+ .withFlag(ForwardingObjective.Flag.SPECIFIC);
+ srManager.flowObjectiveService.
+ forward(deviceId,
+ fwdObjBuilder.
+ add(new SRObjectiveContext(deviceId,
+ SRObjectiveContext.ObjectiveType.FORWARDING)));
+ rulePopulationCounter.incrementAndGet();
+ }
+
+ return true;
+ }
+
+ private ForwardingObjective.Builder getMplsForwardingObjective(DeviceId deviceId,
+ DeviceId destSw,
+ Set<DeviceId> 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.deferred().copyTtlIn();
+ if (isBos) {
+ tbuilder.deferred().popMpls(Ethernet.TYPE_IPV4).decNwTtl();
+ } else {
+ tbuilder.deferred().popMpls(Ethernet.MPLS_UNICAST).decMplsTtl();
+ }
+ } else {
+ log.debug("getMplsForwardingObjective: php not required");
+ tbuilder.deferred().decMplsTtl();
+ }
+
+ if (!isECMPSupportedInTransitRouter() && !config.isEdgeDevice(deviceId)) {
+ PortNumber port = selectOnePort(deviceId, nextHops);
+ DeviceId nextHop = (DeviceId) nextHops.toArray()[0];
+ if (port == null) {
+ log.warn("No link from {} to {}", deviceId, nextHops);
+ return null;
+ }
+ tbuilder.deferred()
+ .setEthSrc(config.getDeviceMac(deviceId))
+ .setEthDst(config.getDeviceMac(nextHop))
+ .setOutput(port);
+ fwdBuilder.withTreatment(tbuilder.build());
+ } else {
+ NeighborSet ns = new NeighborSet(nextHops);
+ fwdBuilder.withTreatment(tbuilder.build());
+ fwdBuilder.nextStep(srManager
+ .getNextObjectiveId(deviceId, ns));
+ }
+
+ return fwdBuilder;
+ }
+
+ private boolean isECMPSupportedInTransitRouter() {
+
+ // TODO: remove this function when objectives subsystem is supported.
+ return false;
+ }
+
+ /**
+ * Populates VLAN flows rules. All packets are forwarded to TMAC table.
+ *
+ * @param deviceId switch ID to set the rules
+ */
+ public void populateTableVlan(DeviceId 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(new SRObjectiveContext(deviceId,
+ SRObjectiveContext.ObjectiveType.FILTER)));
+ }
+
+ /**
+ * 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) {
+
+ 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(new SRObjectiveContext(deviceId,
+ SRObjectiveContext.ObjectiveType.FILTER)));
+ }
+
+ private PortNumber selectOnePort(DeviceId srcId, Set<DeviceId> destIds) {
+
+ Set<Link> links = srManager.linkService.getDeviceLinks(srcId);
+ for (DeviceId destId: destIds) {
+ for (Link link : links) {
+ if (link.dst().deviceId().equals(destId)) {
+ return link.src().port();
+ } else if (link.src().deviceId().equals(destId)) {
+ return link.dst().port();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static class SRObjectiveContext implements ObjectiveContext {
+ enum ObjectiveType {
+ FILTER,
+ FORWARDING
+ }
+ final DeviceId deviceId;
+ final ObjectiveType type;
+
+ SRObjectiveContext(DeviceId deviceId, ObjectiveType type) {
+ this.deviceId = deviceId;
+ this.type = type;
+ }
+ @Override
+ public void onSuccess(Objective objective) {
+ log.debug("{} objective operation successful in device {}",
+ type.name(), deviceId);
+ }
+
+ @Override
+ public void onError(Objective objective, ObjectiveError error) {
+ log.warn("{} objective {} operation failed with error: {} in device {}",
+ type.name(), objective, error, deviceId);
+ }
+ }
+
+}