/* * Copyright 2015-present 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.segmentrouting.config.DeviceConfiguration; 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; /** * Result of policy creation. */ public enum Result { /** * Success. */ SUCCESS, /** * The same policy exists already. */ POLICY_EXISTS, /** * The policy ID exists already. */ ID_EXISTS, /** * Cannot find associated tunnel. */ TUNNEL_NOT_FOUND, /** * Policy was not found. */ POLICY_NOT_FOUND, /** * Policy type {} is not supported yet. */ UNSUPPORTED_TYPE } /** * Constructs policy handler. * * @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(); } }