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.ReadOnlyTransaction;
15 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
18 import org.opendaylight.groupbasedpolicy.api.sf.ChainActionDefinition;
19 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyConfigurationContext;
20 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyManagerImpl;
21 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.NetconfTransactionCreator;
22 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.PolicyWriter;
23 import org.opendaylight.groupbasedpolicy.util.IetfModelCodec;
24 import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
25 import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
26 import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
27 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.RendererPathStates;
28 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.RendererPathState;
29 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.RendererPathStateKey;
30 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.renderer.path.state.ConfiguredRenderedPaths;
31 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.renderer.path.state.configured.rendered.paths.ConfiguredRenderedPath;
32 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.renderer.path.state.configured.rendered.paths.ConfiguredRenderedPathKey;
33 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RendererName;
34 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName;
35 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfcName;
36 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName;
37 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput;
38 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
39 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
40 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
41 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.SffDataPlaneLocator;
42 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.sff.data.plane.locator.DataPlaneLocator;
43 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
44 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
45 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
46 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.LocatorType;
47 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.locator.type.Ip;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
50 import org.opendaylight.yang.gen.v1.urn.ios.rev160308.Native;
51 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMap;
52 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChain;
53 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChainBuilder;
54 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native._class.map.Match;
55 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.config.service.chain.grouping.IpBuilder;
56 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.Class;
57 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePath;
58 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathBuilder;
59 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathKey;
60 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfName;
61 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameBuilder;
62 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameKey;
63 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.ConfigServiceChainPathModeBuilder;
64 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.ServiceIndexBuilder;
65 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.Services;
66 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.ServicesBuilder;
67 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.services.ServiceTypeChoice;
68 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;
69 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;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpoint;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.actions.Action;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
75 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
79 import java.util.ArrayList;
80 import java.util.Collections;
81 import java.util.HashMap;
82 import java.util.List;
84 import java.util.function.Consumer;
85 import java.util.function.Supplier;
87 public class ServiceChainingUtil {
89 private static final Logger LOG = LoggerFactory.getLogger(ServiceChainingUtil.class);
90 private static final String RSP_SUFFIX = "-gbp-rsp";
91 private static final String RSP_REVERSED_SUFFIX = "-gbp-rsp-Reverse";
93 static ServiceFunctionPath getServicePath(final List<ParameterValue> params) {
94 if (params == null || params.isEmpty()) {
95 LOG.error("Cannot found service path, parameter value is null");
98 final Map<String, Object> paramsMap = new HashMap<>();
99 for (ParameterValue value : params) {
100 if (value.getName() == null)
102 if (value.getIntValue() != null) {
103 paramsMap.put(value.getName().getValue(), value.getIntValue());
104 } else if (value.getStringValue() != null) {
105 paramsMap.put(value.getName().getValue(), value.getStringValue());
108 String chainName = null;
109 for (String name : paramsMap.keySet()) {
110 if (name.equals(ChainActionDefinition.SFC_CHAIN_NAME)) {
111 chainName = (String) paramsMap.get(name);
114 if (chainName == null) {
115 LOG.error("Cannot found service path, chain name is null");
118 final ServiceFunctionPath serviceFunctionPath = findServiceFunctionPath(new SfcName(chainName));
119 if (serviceFunctionPath == null) {
120 LOG.error("Service function path not found for name {}", chainName);
123 return serviceFunctionPath;
126 static void resolveNewChainAction(final PeerEndpoint peerEndpoint, final Sgt sourceSgt,
127 final Sgt destinationSgt, final Map<PolicyManagerImpl.ActionCase, Action> actionMap,
128 final PolicyConfigurationContext context, final DataBroker dataBroker) {
129 final List<Class> policyMapEntries = new ArrayList<>();
130 final Action action = actionMap.get(PolicyManagerImpl.ActionCase.CHAIN);
131 final ServiceFunctionPath servicePath = ServiceChainingUtil.getServicePath(action.getParameterValue());
132 if (servicePath == null || servicePath.getName() == null) {
133 final String info = String.format("service-path not found (sourceSgt=%s, destinationSgt=%s)",
134 sourceSgt, destinationSgt);
135 context.appendUnconfiguredRendererEP(StatusUtil.assembleNotConfigurableRendererEPForPeer(context, peerEndpoint, info));
138 final TenantId tenantId = PolicyManagerUtil.getTenantId(peerEndpoint);
139 if (tenantId == null) {
140 final String info = String.format("tenant-id not found (sourceSgt=%s, destinationSgt=%s)",
141 sourceSgt, destinationSgt);
142 context.appendUnconfiguredRendererEP(StatusUtil.assembleNotConfigurableRendererEPForPeer(context, peerEndpoint, info));
145 final RenderedServicePath directPath = ServiceChainingUtil.createRenderedPath(servicePath, tenantId, dataBroker);
146 // Rsp found, create class-map and policy-map entry
147 final String classMapName = PolicyManagerUtil.generateClassMapName(sourceSgt.getValue(), destinationSgt.getValue());
148 final Match match = PolicyManagerUtil.createSecurityGroupMatch(sourceSgt.getValue(), destinationSgt.getValue());
149 final ClassMap classMap = PolicyManagerUtil.createClassMap(classMapName, match);
150 policyMapEntries.add(PolicyManagerUtil.createPolicyEntry(classMapName, directPath, PolicyManagerImpl.ActionCase.CHAIN));
151 RenderedServicePath reversedPath = null;
152 if (servicePath.isSymmetric()) {
153 // symmetric path is in opposite direction. Roles of renderer and peer endpoint will invert
154 reversedPath = ServiceChainingUtil.createSymmetricRenderedPath(servicePath, directPath, tenantId, dataBroker);
155 // Reversed Rsp found, create class-map and policy-map entry in opposite direction
156 final String oppositeClassMapName = PolicyManagerUtil.generateClassMapName(destinationSgt.getValue(), sourceSgt.getValue());
157 final Match oppositeMatch = PolicyManagerUtil.createSecurityGroupMatch(destinationSgt.getValue(), sourceSgt.getValue());
158 final ClassMap oppositeClassMap = PolicyManagerUtil.createClassMap(oppositeClassMapName, oppositeMatch);
159 policyMapEntries.add(PolicyManagerUtil.createPolicyEntry(oppositeClassMapName, reversedPath, PolicyManagerImpl.ActionCase.CHAIN));
160 context.getPolicyWriter().cache(oppositeClassMap);
162 // Create appropriate service path && remote forwarder
163 final boolean sfcPartSuccessful = setSfcPart(servicePath, directPath, reversedPath, context.getPolicyWriter());
164 if (!sfcPartSuccessful) {
165 //TODO: extract resolved-rule name
166 final String info = String.format("failed during sfc-part execution (sourceSgt=%s, destinationSgt=%s)",
167 sourceSgt, destinationSgt);
168 //context.appendUnconfiguredRendererEP(StatusUtil.assembleNotConfigurableRendererEPForPeerAndAction(context, peerEndpoint, info));
171 context.getPolicyWriter().cache(classMap);
172 context.getPolicyWriter().cache(policyMapEntries);
175 static void removeChainAction(final PeerEndpoint peerEndpoint, final Sgt sourceSgt, final Sgt destinationSgt,
176 final Map<PolicyManagerImpl.ActionCase, Action> actionMap, PolicyWriter policyWriter) {
177 final Action action = actionMap.get(PolicyManagerImpl.ActionCase.CHAIN);
178 final ServiceFunctionPath servicePath = ServiceChainingUtil.getServicePath(action.getParameterValue());
179 if (servicePath == null || servicePath.getName() == null) {
182 final TenantId tenantId = PolicyManagerUtil.getTenantId(peerEndpoint);
183 if (tenantId == null) {
186 // Cache class-maps, appropriate policy-map entries and service-path (if there are some created by gbp)
187 final List<Class> policyMapEntries = new ArrayList<>();
188 final String classMapName = PolicyManagerUtil.generateClassMapName(sourceSgt.getValue(), destinationSgt.getValue());
189 final ClassMap classMap = PolicyManagerUtil.createClassMap(classMapName, null);
190 policyWriter.cache(classMap);
191 policyMapEntries.add(PolicyManagerUtil.createPolicyEntry(classMapName, null, PolicyManagerImpl.ActionCase.CHAIN));
193 final RspName rspName = generateRspName(servicePath, tenantId);
194 final RenderedServicePath renderedServicePath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
195 final ServiceFunctionForwarder firstHopSff = getFirstHopSff(renderedServicePath);
196 if (firstHopSff != null && firstHopSff.getIpMgmtAddress() != null &&
197 firstHopSff.getIpMgmtAddress().getIpv4Address() != null) {
198 final String sffMgmtIpValue = firstHopSff.getIpMgmtAddress().getIpv4Address().getValue();
199 if (sffMgmtIpValue.equals(policyWriter.getManagementIpAddress())) {
200 // Remove service chain and remote forwarder
201 final ServiceChain serviceChain = findServiceChainToRsp(renderedServicePath);
202 final ServiceFfName remoteForwarder = findRemoteForwarder(firstHopSff);
203 policyWriter.cache(serviceChain);
204 policyWriter.cache(remoteForwarder);
207 if (servicePath.isSymmetric()) {
208 final String oppositeClassMapName = PolicyManagerUtil.generateClassMapName(destinationSgt.getValue(), sourceSgt.getValue());
209 final ClassMap oppositeClassMap = PolicyManagerUtil.createClassMap(oppositeClassMapName, null);
210 policyWriter.cache(oppositeClassMap);
211 policyMapEntries.add(PolicyManagerUtil.createPolicyEntry(oppositeClassMapName, null, PolicyManagerImpl.ActionCase.CHAIN));
213 final RspName reversedRspName = generateReversedRspName(servicePath, tenantId);
214 final RenderedServicePath reversedRenderedServicePath = SfcProviderRenderedPathAPI.readRenderedServicePath(reversedRspName);
215 final ServiceFunctionForwarder reversedFirstHopSff = getFirstHopSff(reversedRenderedServicePath);
216 if (reversedFirstHopSff != null && reversedFirstHopSff.getIpMgmtAddress() != null &&
217 reversedFirstHopSff.getIpMgmtAddress().getIpv4Address() != null) {
218 final String reversedSffMgmtIpValue = reversedFirstHopSff.getIpMgmtAddress().getIpv4Address().getValue();
219 if (reversedSffMgmtIpValue.equals(policyWriter.getManagementIpAddress())) {
220 // Remove service chain and remote forwarder
221 final ServiceChain serviceChain = findServiceChainToRsp(renderedServicePath);
222 final ServiceFfName remoteForwarder = findRemoteForwarder(reversedFirstHopSff);
223 policyWriter.cache(serviceChain);
224 policyWriter.cache(remoteForwarder);
228 policyWriter.cache(policyMapEntries);
231 private static ServiceFfName findRemoteForwarder(ServiceFunctionForwarder firstHopSff) {
232 ServiceFfNameBuilder serviceFfNameBuilder = new ServiceFfNameBuilder();
233 serviceFfNameBuilder.setName(firstHopSff.getName().getValue())
234 .setKey(new ServiceFfNameKey(firstHopSff.getName().getValue()));
235 return serviceFfNameBuilder.build();
238 private static ServiceFunctionForwarder getFirstHopSff(RenderedServicePath renderedServicePath) {
239 if (renderedServicePath == null || renderedServicePath.getRenderedServicePathHop() == null ||
240 renderedServicePath.getRenderedServicePathHop().isEmpty()) {
243 final RenderedServicePathHop firstHop = renderedServicePath.getRenderedServicePathHop().get(0);
244 final SffName firstHopSff = firstHop.getServiceFunctionForwarder();
245 if (firstHopSff == null) {
248 return SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(firstHopSff);
251 private static ServiceChain findServiceChainToRsp(final RenderedServicePath renderedServicePath) {
252 // Construct service chain with key
253 final Long pathId = renderedServicePath.getPathId();
254 final ServicePathBuilder servicePathBuilder = new ServicePathBuilder();
255 final ServiceChainBuilder serviceChainBuilder = new ServiceChainBuilder();
256 servicePathBuilder.setServicePathId(pathId)
257 .setKey(new ServicePathKey(pathId));
258 serviceChainBuilder.setServicePath(Collections.singletonList(servicePathBuilder.build()));
259 return serviceChainBuilder.build();
262 static RenderedServicePath createRenderedPath(final ServiceFunctionPath sfp, final TenantId tenantId,
263 final DataBroker dataBroker) {
264 RenderedServicePath renderedServicePath;
265 // Try to read existing RSP
266 final RspName rspName = generateRspName(sfp, tenantId);
267 renderedServicePath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
268 if (renderedServicePath != null) {
269 return renderedServicePath;
271 LOG.info("Rendered service path with name {} not found, creating a new one ..", rspName.getValue());
272 final CreateRenderedPathInput input = new CreateRenderedPathInputBuilder()
273 .setParentServiceFunctionPath(sfp.getName().getValue())
274 .setName(rspName.getValue())
275 .setSymmetric(sfp.isSymmetric())
277 renderedServicePath = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, input);
278 LOG.info("Rendered service path {} created", rspName.getValue());
279 checkSfcRspStatus(rspName, dataBroker);
280 return renderedServicePath;
283 static RenderedServicePath createSymmetricRenderedPath(final ServiceFunctionPath sfp, final RenderedServicePath rsp,
284 final TenantId tenantId, final DataBroker dataBroker) {
285 RenderedServicePath reversedRenderedPath;
286 // Try to read existing RSP
287 final RspName rspName = generateReversedRspName(sfp, tenantId);
288 reversedRenderedPath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
289 if (reversedRenderedPath != null) {
290 return reversedRenderedPath;
292 LOG.info("Reversed rendered service path with name {} not found, creating a new one ..", rspName.getValue());
293 reversedRenderedPath = SfcProviderRenderedPathAPI.createReverseRenderedServicePathEntry(rsp);
294 LOG.info("Rendered service path {} created", rspName.getValue());
295 checkSfcRspStatus(rspName, dataBroker);
296 return reversedRenderedPath;
299 static ServiceFunctionPath findServiceFunctionPath(final SfcName chainName) {
300 final ServiceFunctionPaths allPaths = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
301 for (ServiceFunctionPath serviceFunctionPath : allPaths.getServiceFunctionPath()) {
302 if (serviceFunctionPath.getServiceChainName().equals(chainName)) {
303 return serviceFunctionPath;
309 private static RspName generateRspName(final ServiceFunctionPath serviceFunctionPath, final TenantId tenantId) {
310 return new RspName(serviceFunctionPath.getName().getValue() + tenantId.getValue() + RSP_SUFFIX);
313 private static RspName generateReversedRspName(final ServiceFunctionPath serviceFunctionPath, final TenantId tenantId) {
314 return new RspName(serviceFunctionPath.getName().getValue() + tenantId.getValue() + RSP_REVERSED_SUFFIX);
317 private static <T> Supplier<Boolean> createNegativePathWithLogSupplier(final T value, final Consumer<T> logCommand) {
320 logCommand.accept(value);
325 static boolean setSfcPart(final ServiceFunctionPath serviceFunctionPath, final RenderedServicePath renderedServicePath,
326 final RenderedServicePath reversedRenderedServicePath, PolicyWriter policyWriter) {
327 boolean outcome = true;
329 final java.util.Optional<RenderedServicePath> renderedServicePathSafe = java.util.Optional.ofNullable(renderedServicePath);
330 if (renderedServicePathSafe.isPresent()) {
331 if (renderedServicePath.getRenderedServicePathHop() != null
332 && !renderedServicePath.getRenderedServicePathHop().isEmpty()) {
333 if (!resolveRenderedServicePath(renderedServicePath, policyWriter)) {
337 LOG.warn("Rendered service path {} does not contain any hop",
338 renderedServicePathSafe.map(RenderedServicePath::getName).map(RspName::getValue).orElse("n/a"));
342 LOG.warn("Rendered service path is null");
345 if (serviceFunctionPath.isSymmetric()) {
347 final java.util.Optional<RenderedServicePath> reversedRenderedServicePathSafe = java.util.Optional.ofNullable(reversedRenderedServicePath);
348 if (reversedRenderedServicePathSafe.isPresent()) {
349 if (reversedRenderedServicePath.getRenderedServicePathHop() != null
350 && !reversedRenderedServicePath.getRenderedServicePathHop().isEmpty()) {
351 if (!resolveRenderedServicePath(reversedRenderedServicePath, policyWriter)) {
355 LOG.warn("Rendered service path {} does not contain any hop",
356 reversedRenderedServicePathSafe.map(RenderedServicePath::getName).map(RspName::getValue).orElse("n/a"));
360 LOG.warn("Reversed rendered service path is null");
367 private static boolean resolveRenderedServicePath(final RenderedServicePath renderedServicePath, PolicyWriter policyWriter) {
368 final RenderedServicePathHop firstHop = renderedServicePath.getRenderedServicePathHop().get(0);
369 if (firstHop == null) {
372 final SffName sffName = firstHop.getServiceFunctionForwarder();
374 // Create remote forwarder if necessary
375 final java.util.Optional<ServiceFunctionForwarder> serviceFunctionForwarder = java.util.Optional.ofNullable(
376 SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(sffName));
377 if (!serviceFunctionForwarder.isPresent()) {
378 LOG.warn("Service function forwarder {} does not exist", sffName.getValue());
381 final ServiceFunctionForwarder forwarder = serviceFunctionForwarder.get();
382 if (forwarder.getSffDataPlaneLocator() == null || forwarder.getSffDataPlaneLocator().isEmpty()) {
383 LOG.warn("Service function forwarder {} does not contain data plane locator", sffName.getValue());
386 // TODO only first dpl resolved
387 final SffDataPlaneLocator sffDataPlaneLocator = forwarder.getSffDataPlaneLocator().get(0);
388 final DataPlaneLocator dataPlaneLocator = sffDataPlaneLocator.getDataPlaneLocator();
389 final LocatorType locatorType = dataPlaneLocator.getLocatorType();
390 if (locatorType != null && locatorType instanceof Ip) {
391 final IpAddress remoteForwarderIpAddress = IetfModelCodec.ipAddress2010(((Ip) locatorType).getIp());
392 if (remoteForwarderIpAddress == null || remoteForwarderIpAddress.getIpv4Address() == null) {
393 LOG.warn("Service function forwarder {} data plane locator does not contain ip address", sffName.getValue());
396 final String remoteForwarderStringIp = remoteForwarderIpAddress.getIpv4Address().getValue();
397 return serviceFunctionForwarder.map(sff -> java.util.Optional.ofNullable(sff.getIpMgmtAddress())
398 .map(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress::getIpv4Address)
399 .map(Ipv4Address::getValue)
400 .map(addressValue -> {
401 final ServiceTypeChoice serviceTypeChoice;
402 if (!addressValue.equals(policyWriter.getManagementIpAddress())) {
403 final ServiceFfNameBuilder remoteSffBuilder = new ServiceFfNameBuilder();
404 remoteSffBuilder.setName(sffName.getValue())
405 .setKey(new ServiceFfNameKey(sffName.getValue()))
406 .setIp(new IpBuilder().setAddress(new Ipv4Address(remoteForwarderStringIp)).build());
407 policyWriter.cache(remoteSffBuilder.build());
408 serviceTypeChoice = forwarderTypeChoice(sffName.getValue());
410 final List<Services> services = new ArrayList<>();
411 final ServicesBuilder servicesBuilder = new ServicesBuilder();
412 servicesBuilder.setServiceIndexId(renderedServicePath.getStartingIndex())
413 .setServiceTypeChoice(serviceTypeChoice);
414 services.add(servicesBuilder.build());
415 final List<ServicePath> servicePaths = new ArrayList<>();
416 final ServicePathBuilder servicePathBuilder = new ServicePathBuilder();
417 servicePathBuilder.setKey(new ServicePathKey(renderedServicePath.getPathId()))
418 .setServicePathId(renderedServicePath.getPathId())
419 .setConfigServiceChainPathMode(new ConfigServiceChainPathModeBuilder()
420 .setServiceIndex(new ServiceIndexBuilder()
421 .setServices(services).build()).build());
422 servicePaths.add(servicePathBuilder.build());
423 final ServiceChainBuilder chainBuilder = new ServiceChainBuilder();
424 chainBuilder.setServicePath(servicePaths);
425 final ServiceChain serviceChain = chainBuilder.build();
426 policyWriter.cache(serviceChain);
429 }).orElseGet(createNegativePathWithLogSupplier(sffName.getValue(),
430 (value) -> LOG.error("Cannot create remote forwarder, SFF {} does not contain management ip address",
433 ).orElseGet(createNegativePathWithLogSupplier(sffName.getValue(),
434 (value) -> LOG.error("Sff with name {} does not exist", value))
440 static ServiceTypeChoice forwarderTypeChoice(final String forwarderName) {
441 final ServiceFunctionForwarderBuilder sffBuilder = new ServiceFunctionForwarderBuilder();
442 sffBuilder.setServiceFunctionForwarder(forwarderName);
443 return sffBuilder.build();
446 static ServiceTypeChoice functionTypeChoice(final String functionName) {
447 final ServiceFunctionBuilder sfBuilder = new ServiceFunctionBuilder();
448 sfBuilder.setServiceFunction(functionName);
449 return sfBuilder.build();
452 private static void checkSfcRspStatus(final RspName rspName, final DataBroker dataBroker) {
453 /** TODO A better way to do this is to register listener and wait for notification than using hardcoded timeout
454 * with Thread.sleep(). Example in class BridgeDomainManagerImpl
456 ConfiguredRenderedPath renderedPath = null;
457 LOG.info("Waiting for SFC to configure path {} ...", rspName.getValue());
465 } catch (InterruptedException e) {
466 LOG.error("Thread interrupted while waiting ... {} ", e);
468 // Read actual status
469 final InstanceIdentifier<ConfiguredRenderedPath> statusIid = InstanceIdentifier.builder(RendererPathStates.class)
470 .child(RendererPathState.class, new RendererPathStateKey(new RendererName("ios-xe-renderer")))
471 .child(ConfiguredRenderedPaths.class)
472 .child(ConfiguredRenderedPath.class, new ConfiguredRenderedPathKey(rspName)).build();
473 final java.util.Optional<ReadWriteTransaction> optionalTransaction =
474 NetconfTransactionCreator.netconfReadWriteTransaction(dataBroker);
475 if (!optionalTransaction.isPresent()) {
476 LOG.warn("Failed to create transaction, mountpoint: {}", dataBroker);
479 ReadWriteTransaction transaction = optionalTransaction.get();
481 final CheckedFuture<Optional<ConfiguredRenderedPath>, ReadFailedException> submitFuture =
482 transaction.read(LogicalDatastoreType.OPERATIONAL, statusIid);
483 final Optional<ConfiguredRenderedPath> optionalPath = submitFuture.checkedGet();
484 if (optionalPath.isPresent()) {
485 renderedPath = optionalPath.get();
487 } catch (ReadFailedException e) {
488 LOG.warn("Failed while read rendered path status ... {} ", e.getMessage());
490 if (renderedPath == null || renderedPath.getPathStatus() == null ||
491 renderedPath.getPathStatus().equals(ConfiguredRenderedPath.PathStatus.InProgress)) {
492 LOG.info("Still waiting for SFC ... ");
493 } else if (renderedPath.getPathStatus().equals(ConfiguredRenderedPath.PathStatus.Failure)) {
494 LOG.warn("SFC failed to configure rsp");
495 } else if (renderedPath.getPathStatus().equals(ConfiguredRenderedPath.PathStatus.Success)) {
496 LOG.info("RSP {} configured by SFC", rspName.getValue());
498 Thread.sleep(5000); // Just for sure, maybe will be safe to remove this
499 } catch (InterruptedException e) {
500 LOG.error("Thread interrupted while waiting ... {} ", e);
505 while (attempt <= 6);
506 LOG.warn("Maximum number of attempts reached");