| /* |
| * 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.IpPrefix; |
| import org.onlab.packet.TpPort; |
| import org.onosproject.cli.net.IpProtocol; |
| import org.onosproject.core.ApplicationId; |
| import org.onosproject.net.DeviceId; |
| import org.onosproject.net.flow.DefaultTrafficSelector; |
| import org.onosproject.net.flow.TrafficSelector; |
| import org.onosproject.net.flowobjective.DefaultForwardingObjective; |
| import org.onosproject.net.flowobjective.FlowObjectiveService; |
| import org.onosproject.net.flowobjective.ForwardingObjective; |
| import org.onosproject.store.service.EventuallyConsistentMap; |
| import org.slf4j.Logger; |
| |
| import java.util.List; |
| import java.util.stream.Collectors; |
| |
| import static org.slf4j.LoggerFactory.getLogger; |
| |
| /** |
| * Segment Routing Policy Handler. |
| */ |
| public class PolicyHandler { |
| |
| protected final Logger log = getLogger(getClass()); |
| |
| private ApplicationId appId; |
| private DeviceConfiguration deviceConfiguration; |
| private FlowObjectiveService flowObjectiveService; |
| private TunnelHandler tunnelHandler; |
| private final EventuallyConsistentMap<String, Policy> policyStore; |
| |
| public enum Result { |
| SUCCESS, |
| POLICY_EXISTS, |
| ID_EXISTS, |
| TUNNEL_NOT_FOUND, |
| POLICY_NOT_FOUND, |
| UNSUPPORTED_TYPE |
| } |
| |
| /** |
| * Creates a reference. |
| * |
| * @param appId segment routing application ID |
| * @param deviceConfiguration DeviceConfiguration reference |
| * @param flowObjectiveService FlowObjectiveService reference |
| * @param tunnelHandler tunnel handler reference |
| * @param policyStore policy store |
| */ |
| public PolicyHandler(ApplicationId appId, |
| DeviceConfiguration deviceConfiguration, |
| FlowObjectiveService flowObjectiveService, |
| TunnelHandler tunnelHandler, |
| EventuallyConsistentMap<String, Policy> policyStore) { |
| this.appId = appId; |
| this.deviceConfiguration = deviceConfiguration; |
| this.flowObjectiveService = flowObjectiveService; |
| this.tunnelHandler = tunnelHandler; |
| this.policyStore = policyStore; |
| } |
| |
| /** |
| * Returns the policies. |
| * |
| * @return policy list |
| */ |
| public List<Policy> getPolicies() { |
| return policyStore.values() |
| .stream() |
| .filter(policy -> policy instanceof TunnelPolicy) |
| .map(policy -> new TunnelPolicy((TunnelPolicy) policy)) |
| .collect(Collectors.toList()); |
| } |
| |
| /** |
| * Creates a policy using the policy information given. |
| * @param policy policy reference to create |
| * @return ID_EXISTS if the same policy ID exists, |
| * POLICY_EXISTS if the same policy exists, TUNNEL_NOT_FOUND if the tunnel |
| * does not exists, UNSUPPORTED_TYPE if the policy type is not supported, |
| * SUCCESS if the policy is created successfully |
| */ |
| public Result createPolicy(Policy policy) { |
| |
| if (policyStore.containsKey(policy.id())) { |
| log.warn("The policy id {} exists already", policy.id()); |
| return Result.ID_EXISTS; |
| } |
| |
| if (policyStore.containsValue(policy)) { |
| log.warn("The same policy exists already"); |
| return Result.POLICY_EXISTS; |
| } |
| |
| if (policy.type() == Policy.Type.TUNNEL_FLOW) { |
| |
| TunnelPolicy tunnelPolicy = (TunnelPolicy) policy; |
| Tunnel tunnel = tunnelHandler.getTunnel(tunnelPolicy.tunnelId()); |
| if (tunnel == null) { |
| return Result.TUNNEL_NOT_FOUND; |
| } |
| |
| ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective |
| .builder() |
| .fromApp(appId) |
| .makePermanent() |
| .nextStep(tunnel.groupId()) |
| .withPriority(tunnelPolicy.priority()) |
| .withSelector(buildSelector(policy)) |
| .withFlag(ForwardingObjective.Flag.VERSATILE); |
| |
| DeviceId source = deviceConfiguration.getDeviceId(tunnel.labelIds().get(0)); |
| flowObjectiveService.forward(source, fwdBuilder.add()); |
| |
| } else { |
| log.warn("Policy type {} is not supported yet.", policy.type()); |
| return Result.UNSUPPORTED_TYPE; |
| } |
| |
| policyStore.put(policy.id(), policy); |
| |
| return Result.SUCCESS; |
| } |
| |
| /** |
| * Removes the policy given. |
| * |
| * @param policyInfo policy information to remove |
| * @return POLICY_NOT_FOUND if the policy to remove does not exists, |
| * SUCCESS if it is removed successfully |
| */ |
| public Result removePolicy(Policy policyInfo) { |
| |
| if (policyStore.get(policyInfo.id()) != null) { |
| Policy policy = policyStore.get(policyInfo.id()); |
| if (policy.type() == Policy.Type.TUNNEL_FLOW) { |
| TunnelPolicy tunnelPolicy = (TunnelPolicy) policy; |
| Tunnel tunnel = tunnelHandler.getTunnel(tunnelPolicy.tunnelId()); |
| |
| ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective |
| .builder() |
| .fromApp(appId) |
| .makePermanent() |
| .withSelector(buildSelector(policy)) |
| .withPriority(tunnelPolicy.priority()) |
| .nextStep(tunnel.groupId()) |
| .withFlag(ForwardingObjective.Flag.VERSATILE); |
| |
| DeviceId source = deviceConfiguration.getDeviceId(tunnel.labelIds().get(0)); |
| flowObjectiveService.forward(source, fwdBuilder.remove()); |
| |
| policyStore.remove(policyInfo.id()); |
| } |
| } else { |
| log.warn("Policy {} was not found", policyInfo.id()); |
| return Result.POLICY_NOT_FOUND; |
| } |
| |
| return Result.SUCCESS; |
| } |
| |
| |
| private TrafficSelector buildSelector(Policy policy) { |
| |
| TrafficSelector.Builder tsb = DefaultTrafficSelector.builder(); |
| tsb.matchEthType(Ethernet.TYPE_IPV4); |
| if (policy.dstIp() != null && !policy.dstIp().isEmpty()) { |
| tsb.matchIPDst(IpPrefix.valueOf(policy.dstIp())); |
| } |
| if (policy.srcIp() != null && !policy.srcIp().isEmpty()) { |
| tsb.matchIPSrc(IpPrefix.valueOf(policy.srcIp())); |
| } |
| if (policy.ipProto() != null && !policy.ipProto().isEmpty()) { |
| Short ipProto = IpProtocol.valueOf(policy.ipProto()).value(); |
| tsb.matchIPProtocol(ipProto.byteValue()); |
| if (IpProtocol.valueOf(policy.ipProto()).equals(IpProtocol.TCP)) { |
| if (policy.srcPort() != 0) { |
| tsb.matchTcpSrc(TpPort.tpPort(policy.srcPort())); |
| } |
| if (policy.dstPort() != 0) { |
| tsb.matchTcpDst(TpPort.tpPort(policy.dstPort())); |
| } |
| } else if (IpProtocol.valueOf(policy.ipProto()).equals(IpProtocol.UDP)) { |
| if (policy.srcPort() != 0) { |
| tsb.matchUdpSrc(TpPort.tpPort(policy.srcPort())); |
| } |
| if (policy.dstPort() != 0) { |
| tsb.matchUdpDst(TpPort.tpPort(policy.dstPort())); |
| } |
| } |
| } |
| |
| return tsb.build(); |
| } |
| |
| } |