2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util;
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.CheckedFuture;
13 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
14 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
17 import org.opendaylight.groupbasedpolicy.api.sf.ChainActionDefinition;
18 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyManagerImpl;
19 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.PolicyWriter;
20 import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
21 import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
22 import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
23 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName;
24 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfcName;
25 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName;
26 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput;
27 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
28 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
29 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
30 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
31 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
32 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
34 import org.opendaylight.yang.gen.v1.urn.ios.rev160308.Native;
35 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChain;
36 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChainBuilder;
37 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.config.service.chain.grouping.IpBuilder;
38 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.Class;
39 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePath;
40 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathBuilder;
41 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathKey;
42 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.Local;
43 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.LocalBuilder;
44 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameBuilder;
45 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameKey;
46 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.ConfigServiceChainPathModeBuilder;
47 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.ServiceIndexBuilder;
48 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.Services;
49 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.ServicesBuilder;
50 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.services.ServiceTypeChoice;
51 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.services.service.type.choice.ServiceFunctionBuilder;
52 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.services.service.type.choice.ServiceFunctionForwarderBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpointWithPolicy;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.actions.Action;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
58 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
62 import java.util.ArrayList;
63 import java.util.HashMap;
64 import java.util.List;
67 public class ServiceChainingUtil {
69 private static final Logger LOG = LoggerFactory.getLogger(ServiceChainingUtil.class);
71 static ServiceFunctionPath getServicePath(final List<ParameterValue> params) {
72 if (params == null || params.isEmpty()) {
73 LOG.error("Cannot found service path, parameter value is null");
76 final Map<String, Object> paramsMap = new HashMap<>();
77 for (ParameterValue value : params) {
78 if (value.getName() == null)
80 if (value.getIntValue() != null) {
81 paramsMap.put(value.getName().getValue(), value.getIntValue());
82 } else if (value.getStringValue() != null) {
83 paramsMap.put(value.getName().getValue(), value.getStringValue());
86 String chainName = null;
87 for (String name : paramsMap.keySet()) {
88 if (name.equals(ChainActionDefinition.SFC_CHAIN_NAME)) {
89 chainName = (String) paramsMap.get(name);
92 if (chainName == null) {
93 LOG.error("Cannot found service path, chain name is null");
96 final ServiceFunctionPath serviceFunctionPath = findServiceFunctionPath(new SfcName(chainName));
97 if (serviceFunctionPath == null) {
98 LOG.error("Service function path not found for name {}", chainName);
101 return serviceFunctionPath;
104 static void resolveChainAction(final PeerEndpointWithPolicy peerEndpoint, final Sgt sourceSgt,
105 final Sgt destinationSgt, final Map<PolicyManagerImpl.ActionCase, Action> actionMap,
106 final String classMapName, PolicyWriter policyWriter) {
107 final List<Class> entries = new ArrayList<>();
108 final Action action = actionMap.get(PolicyManagerImpl.ActionCase.CHAIN);
109 final ServiceFunctionPath servicePath = ServiceChainingUtil.getServicePath(action.getParameterValue());
110 if (servicePath == null) {
113 final TenantId tenantId = PolicyManagerUtil.getTenantId(peerEndpoint);
114 if (tenantId == null) {
117 final RenderedServicePath renderedPath = ServiceChainingUtil.createRenderedPath(servicePath, tenantId);
118 // Create appropriate service path && remote forwarder
119 setSfcPart(renderedPath, policyWriter);
121 entries.add(PolicyManagerUtil.createPolicyEntry(classMapName, renderedPath, PolicyManagerImpl.ActionCase.CHAIN));
122 if (servicePath.isSymmetric()) {
123 // symmetric path is in opposite direction. Roles of renderer and peer endpoint will invert
124 RenderedServicePath symmetricPath = ServiceChainingUtil
125 .createSymmetricRenderedPath(servicePath, renderedPath, tenantId);
126 final String oppositeClassMapName = PolicyManagerUtil.generateClassMapName(destinationSgt.getValue(), sourceSgt.getValue());
127 entries.add(PolicyManagerUtil.createPolicyEntry(oppositeClassMapName, symmetricPath, PolicyManagerImpl.ActionCase.CHAIN));
129 policyWriter.cache(entries);
132 static RenderedServicePath createRenderedPath(final ServiceFunctionPath sfp, final TenantId tenantId) {
133 RenderedServicePath renderedServicePath;
134 // Try to read existing RSP
135 final RspName rspName = new RspName(sfp.getName().getValue() + tenantId.getValue() + "-gbp-rsp");
136 renderedServicePath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
137 if (renderedServicePath != null) {
138 return renderedServicePath;
140 LOG.info("Rendered service path with name {} not found, creating a new one ..", rspName.getValue());
141 final CreateRenderedPathInput input = new CreateRenderedPathInputBuilder()
142 .setParentServiceFunctionPath(sfp.getName().getValue())
143 .setName(rspName.getValue())
144 .setSymmetric(sfp.isSymmetric())
146 renderedServicePath = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, input);
147 LOG.info("Rendered service path {} created", rspName.getValue());
148 return renderedServicePath;
151 static RenderedServicePath createSymmetricRenderedPath(final ServiceFunctionPath sfp, final RenderedServicePath rsp,
152 final TenantId tenantId) {
153 RenderedServicePath reversedRenderedPath;
154 // Try to read existing RSP
155 final RspName rspName = new RspName(sfp.getName().getValue() + tenantId.getValue() + "-gbp-rsp-Reverse");
156 reversedRenderedPath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
157 if (reversedRenderedPath != null) {
158 return reversedRenderedPath;
160 LOG.info("Reversed rendered service path with name {} not found, creating a new one ..", rspName.getValue());
161 reversedRenderedPath = SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
162 LOG.info("Rendered service path {} created", rspName.getValue());
163 return reversedRenderedPath;
167 * Method checks up, whether a {@link Local} Service Function Forwarder is present on device or not.
169 * @param mountpoint used to access specific device
170 * @return true if Local Forwarder is present, false otherwise
172 private static boolean checkLocalForwarderPresence(DataBroker mountpoint) {
173 InstanceIdentifier<Local> localSffIid = InstanceIdentifier.builder(Native.class)
174 .child(ServiceChain.class)
175 .child(org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServiceFunctionForwarder.class)
176 .child(Local.class).build();
177 ReadWriteTransaction rwt = mountpoint.newReadWriteTransaction();
178 CheckedFuture<Optional<Local>, ReadFailedException> submitFuture = rwt.read(LogicalDatastoreType.CONFIGURATION,
181 Optional<Local> optionalLocalSff = submitFuture.checkedGet();
182 return optionalLocalSff.isPresent();
183 } catch (ReadFailedException e) {
184 LOG.warn("Read transaction failed to {} ", e);
185 } catch (Exception e) {
186 LOG.error("Failed to .. {}", e.getMessage());
192 * Method checks up, if some {@link ServicePath} is present on device.
194 * @param mountpoint used to access specific device
195 * @return true if service chain does not exist, is null or does not contain any service path. False otherwise
197 public static boolean checkServicePathPresence(DataBroker mountpoint) {
198 InstanceIdentifier<ServiceChain> serviceChainIid = InstanceIdentifier.builder(Native.class)
199 .child(ServiceChain.class).build();
200 ReadWriteTransaction rwt = mountpoint.newReadWriteTransaction();
201 CheckedFuture<Optional<ServiceChain>, ReadFailedException> submitFuture = rwt.read(LogicalDatastoreType.CONFIGURATION,
204 Optional<ServiceChain> optionalServiceChain = submitFuture.checkedGet();
205 if (optionalServiceChain.isPresent()) {
206 ServiceChain chain = optionalServiceChain.get();
207 return chain == null || chain.getServicePath() == null || chain.getServicePath().isEmpty();
211 } catch (ReadFailedException e) {
212 LOG.warn("Read transaction failed to {} ", e);
213 } catch (Exception e) {
214 LOG.error("Failed to .. {}", e.getMessage());
219 private static ServiceFunctionPath findServiceFunctionPath(final SfcName chainName) {
220 final ServiceFunctionPaths allPaths = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
221 for (ServiceFunctionPath serviceFunctionPath : allPaths.getServiceFunctionPath()) {
222 if (serviceFunctionPath.getServiceChainName().equals(chainName)) {
223 return serviceFunctionPath;
229 private static void setSfcPart(final RenderedServicePath renderedServicePath, PolicyWriter policyWriter) {
230 if (renderedServicePath != null && renderedServicePath.getRenderedServicePathHop() != null &&
231 !renderedServicePath.getRenderedServicePathHop().isEmpty()) {
232 final RenderedServicePathHop firstHop = renderedServicePath.getRenderedServicePathHop().get(0);
233 if (firstHop == null) {
234 LOG.error("Rendered service path {} does not contain any hop", renderedServicePath.getName().getValue());
237 final SffName sffName = firstHop.getServiceFunctionForwarder();
238 final ServiceFunctionForwarder serviceFunctionForwarder = SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(sffName);
239 if (serviceFunctionForwarder == null) {
240 LOG.error("Sff with name {} does not exist", sffName.getValue());
245 // If classifier node is also forwarder, first entry in service path has to point to first service function
248 // If first hop Sff is on different node, first service path entry has to point to that specific service
249 // forwarder (Remote case)
251 // Local case (only when does not exist)
253 if (!checkLocalForwarderPresence(policyWriter.getCurrentMountpoint())) {
254 final LocalBuilder localSffBuilder = new LocalBuilder();
255 localSffBuilder.setIp(new IpBuilder().setAddress(new Ipv4Address(policyWriter.getManagementIpAddress()))
257 policyWriter.cache(localSffBuilder.build());
259 LOG.info("Local forwarder for node {} is already created", policyWriter.getCurrentNodeId());
261 // Set up choice. If remote, this choice is overwritten
262 ServiceTypeChoice serviceTypeChoice = functionTypeChoice(firstHop.getServiceFunctionName().getValue());
264 if (serviceFunctionForwarder.getIpMgmtAddress() == null
265 || serviceFunctionForwarder.getIpMgmtAddress().getIpv4Address() == null) {
266 LOG.error("Cannot create remote forwarder, SFF {} does not contain management ip address",
270 final String sffMgmtIpAddress = serviceFunctionForwarder.getIpMgmtAddress().getIpv4Address().getValue();
271 // If local SFF has the same ip as first hop sff, it's the same SFF; no need to create a remote one
272 if (!sffMgmtIpAddress.equals(policyWriter.getManagementIpAddress())) {
273 final ServiceFfNameBuilder remoteSffBuilder = new ServiceFfNameBuilder();
274 remoteSffBuilder.setName(sffName.getValue())
275 .setKey(new ServiceFfNameKey(sffName.getValue()))
276 .setIp(new IpBuilder().setAddress(new Ipv4Address(sffMgmtIpAddress)).build());
277 policyWriter.cache(remoteSffBuilder.build());
278 serviceTypeChoice = forwarderTypeChoice(sffName.getValue());
282 final List<Services> services = new ArrayList<>();
283 final ServicesBuilder servicesBuilder = new ServicesBuilder();
284 servicesBuilder.setServiceIndexId(renderedServicePath.getStartingIndex())
285 .setServiceTypeChoice(serviceTypeChoice);
286 final List<ServicePath> servicePaths = new ArrayList<>();
287 final ServicePathBuilder servicePathBuilder = new ServicePathBuilder();
288 servicePathBuilder.setKey(new ServicePathKey(renderedServicePath.getPathId()))
289 .setServicePathId(renderedServicePath.getPathId())
290 .setConfigServiceChainPathMode(new ConfigServiceChainPathModeBuilder()
291 .setServiceIndex(new ServiceIndexBuilder()
292 .setServices(services).build()).build());
293 servicePaths.add(servicePathBuilder.build());
294 final ServiceChainBuilder chainBuilder = new ServiceChainBuilder();
295 chainBuilder.setServicePath(servicePaths);
296 final ServiceChain serviceChain = chainBuilder.build();
297 policyWriter.cache(serviceChain);
301 private static ServiceTypeChoice forwarderTypeChoice(final String forwarderName) {
302 final ServiceFunctionForwarderBuilder sffBuilder = new ServiceFunctionForwarderBuilder();
303 sffBuilder.setServiceFunctionForwarder(forwarderName);
304 return sffBuilder.build();
307 private static ServiceTypeChoice functionTypeChoice(final String functionName) {
308 final ServiceFunctionBuilder sfBuilder = new ServiceFunctionBuilder();
309 sfBuilder.setServiceFunction(functionName);
310 return sfBuilder.build();