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.sfc.provider.api.SfcProviderRenderedPathAPI;
24 import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
25 import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
26 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.RendererPathStates;
27 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.RendererPathState;
28 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.RendererPathStateKey;
29 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.renderer.path.state.ConfiguredRenderedPaths;
30 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.renderer.path.state.configured.rendered.paths.ConfiguredRenderedPath;
31 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.renderer.path.state.configured.rendered.paths.ConfiguredRenderedPathKey;
32 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RendererName;
33 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName;
34 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfcName;
35 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName;
36 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput;
37 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
39 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
40 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
41 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
42 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
45 import org.opendaylight.yang.gen.v1.urn.ios.rev160308.Native;
46 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMap;
47 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChain;
48 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChainBuilder;
49 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native._class.map.Match;
50 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.config.service.chain.grouping.IpBuilder;
51 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.Class;
52 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePath;
53 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathBuilder;
54 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathKey;
55 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.Local;
56 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.LocalBuilder;
57 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameBuilder;
58 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameKey;
59 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.ConfigServiceChainPathModeBuilder;
60 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.ServiceIndexBuilder;
61 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.Services;
62 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.ServicesBuilder;
63 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.services.ServiceTypeChoice;
64 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;
65 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;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpoint;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.actions.Action;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
71 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
72 import org.slf4j.Logger;
73 import org.slf4j.LoggerFactory;
75 import java.security.cert.PKIXRevocationChecker;
76 import java.util.ArrayList;
77 import java.util.Collections;
78 import java.util.HashMap;
79 import java.util.List;
81 import java.util.function.Consumer;
82 import java.util.function.Supplier;
84 public class ServiceChainingUtil {
86 private static final Logger LOG = LoggerFactory.getLogger(ServiceChainingUtil.class);
87 private static final String RSP_SUFFIX = "-gbp-rsp";
88 private static final String RSP_REVERSED_SUFFIX = "-gbp-rsp-Reverse";
90 static ServiceFunctionPath getServicePath(final List<ParameterValue> params) {
91 if (params == null || params.isEmpty()) {
92 LOG.error("Cannot found service path, parameter value is null");
95 final Map<String, Object> paramsMap = new HashMap<>();
96 for (ParameterValue value : params) {
97 if (value.getName() == null)
99 if (value.getIntValue() != null) {
100 paramsMap.put(value.getName().getValue(), value.getIntValue());
101 } else if (value.getStringValue() != null) {
102 paramsMap.put(value.getName().getValue(), value.getStringValue());
105 String chainName = null;
106 for (String name : paramsMap.keySet()) {
107 if (name.equals(ChainActionDefinition.SFC_CHAIN_NAME)) {
108 chainName = (String) paramsMap.get(name);
111 if (chainName == null) {
112 LOG.error("Cannot found service path, chain name is null");
115 final ServiceFunctionPath serviceFunctionPath = findServiceFunctionPath(new SfcName(chainName));
116 if (serviceFunctionPath == null) {
117 LOG.error("Service function path not found for name {}", chainName);
120 return serviceFunctionPath;
123 static void resolveNewChainAction(final PeerEndpoint peerEndpoint, final Sgt sourceSgt,
124 final Sgt destinationSgt, final Map<PolicyManagerImpl.ActionCase, Action> actionMap,
125 final PolicyConfigurationContext context, final DataBroker dataBroker) {
126 final List<Class> policyMapEntries = new ArrayList<>();
127 final Action action = actionMap.get(PolicyManagerImpl.ActionCase.CHAIN);
128 final ServiceFunctionPath servicePath = ServiceChainingUtil.getServicePath(action.getParameterValue());
129 if (servicePath == null || servicePath.getName() == null) {
130 final String info = String.format("service-path not found (sourceSgt=%s, destinationSgt=%s)",
131 sourceSgt, destinationSgt);
132 context.appendUnconfiguredRendererEP(StatusUtil.assembleNotConfigurableRendererEPForPeer(context, peerEndpoint, info));
135 final TenantId tenantId = PolicyManagerUtil.getTenantId(peerEndpoint);
136 if (tenantId == null) {
137 final String info = String.format("tenant-id not found (sourceSgt=%s, destinationSgt=%s)",
138 sourceSgt, destinationSgt);
139 context.appendUnconfiguredRendererEP(StatusUtil.assembleNotConfigurableRendererEPForPeer(context, peerEndpoint, info));
142 final RenderedServicePath directPath = ServiceChainingUtil.createRenderedPath(servicePath, tenantId, dataBroker);
143 // Rsp found, create class-map and policy-map entry
144 final String classMapName = PolicyManagerUtil.generateClassMapName(sourceSgt.getValue(), destinationSgt.getValue());
145 final Match match = PolicyManagerUtil.createSecurityGroupMatch(sourceSgt.getValue(), destinationSgt.getValue());
146 final ClassMap classMap = PolicyManagerUtil.createClassMap(classMapName, match);
147 policyMapEntries.add(PolicyManagerUtil.createPolicyEntry(classMapName, directPath, PolicyManagerImpl.ActionCase.CHAIN));
148 RenderedServicePath reversedPath = null;
149 if (servicePath.isSymmetric()) {
150 // symmetric path is in opposite direction. Roles of renderer and peer endpoint will invert
151 reversedPath = ServiceChainingUtil.createSymmetricRenderedPath(servicePath, directPath, tenantId, dataBroker);
152 // Reversed Rsp found, create class-map and policy-map entry in opposite direction
153 final String oppositeClassMapName = PolicyManagerUtil.generateClassMapName(destinationSgt.getValue(), sourceSgt.getValue());
154 final Match oppositeMatch = PolicyManagerUtil.createSecurityGroupMatch(destinationSgt.getValue(), sourceSgt.getValue());
155 final ClassMap oppositeClassMap = PolicyManagerUtil.createClassMap(oppositeClassMapName, oppositeMatch);
156 policyMapEntries.add(PolicyManagerUtil.createPolicyEntry(oppositeClassMapName, reversedPath, PolicyManagerImpl.ActionCase.CHAIN));
157 context.getPolicyWriter().cache(oppositeClassMap);
159 // Create appropriate service path && remote forwarder
160 final boolean sfcPartSuccessful = setSfcPart(servicePath, directPath, reversedPath, context.getPolicyWriter());
161 if (!sfcPartSuccessful) {
162 //TODO: extract resolved-rule name
163 final String info = String.format("failed during sfc-part execution (sourceSgt=%s, destinationSgt=%s)",
164 sourceSgt, destinationSgt);
165 //context.appendUnconfiguredRendererEP(StatusUtil.assembleNotConfigurableRendererEPForPeerAndAction(context, peerEndpoint, info));
168 context.getPolicyWriter().cache(classMap);
169 context.getPolicyWriter().cache(policyMapEntries);
172 static void removeChainAction(final PeerEndpoint peerEndpoint, final Sgt sourceSgt, final Sgt destinationSgt,
173 final Map<PolicyManagerImpl.ActionCase, Action> actionMap, PolicyWriter policyWriter) {
174 final Action action = actionMap.get(PolicyManagerImpl.ActionCase.CHAIN);
175 final ServiceFunctionPath servicePath = ServiceChainingUtil.getServicePath(action.getParameterValue());
176 if (servicePath == null || servicePath.getName() == null) {
179 final TenantId tenantId = PolicyManagerUtil.getTenantId(peerEndpoint);
180 if (tenantId == null) {
183 // Cache class-maps, appropriate policy-map entries and service-chains
184 final List<Class> policyMapEntries = new ArrayList<>();
185 final String classMapName = PolicyManagerUtil.generateClassMapName(sourceSgt.getValue(), destinationSgt.getValue());
186 final ClassMap classMap = PolicyManagerUtil.createClassMap(classMapName, null);
187 final RspName rspName = generateRspName(servicePath, tenantId);
188 final ServiceChain serviceChain = findServiceChainToRsp(rspName);
189 policyMapEntries.add(PolicyManagerUtil.createPolicyEntry(classMapName, null, PolicyManagerImpl.ActionCase.CHAIN));
190 policyWriter.cache(classMap);
191 policyWriter.cache(serviceChain);
192 if (servicePath.isSymmetric()) {
193 final String oppositeClassMapName = PolicyManagerUtil.generateClassMapName(destinationSgt.getValue(), sourceSgt.getValue());
194 final ClassMap oppositeClassMap = PolicyManagerUtil.createClassMap(oppositeClassMapName, null);
195 final RspName reversedRspName = generateReversedRspName(servicePath, tenantId);
196 final ServiceChain reversedServiceChain = findServiceChainToRsp(reversedRspName);
197 policyMapEntries.add(PolicyManagerUtil.createPolicyEntry(oppositeClassMapName, null, PolicyManagerImpl.ActionCase.CHAIN));
198 policyWriter.cache(oppositeClassMap);
199 policyWriter.cache(reversedServiceChain);
201 policyWriter.cache(policyMapEntries);
202 // TODO remove other sfc stuff - forwarders, etc.
205 private static ServiceChain findServiceChainToRsp(final RspName rspName) {
206 // Do not actually remove rsp from DS, could be used by someone else
207 final RenderedServicePath renderedServicePath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
208 if (renderedServicePath == null) {
209 LOG.debug("Rendered service path not found, if there is service-path created according to that rsp, " +
210 "it cannot be removed. Rendered path name: {} ", rspName.getValue());
213 // Construct service chain with key
214 final Long pathId = renderedServicePath.getPathId();
215 final ServicePathBuilder servicePathBuilder = new ServicePathBuilder();
216 final ServiceChainBuilder serviceChainBuilder = new ServiceChainBuilder();
217 servicePathBuilder.setServicePathId(pathId)
218 .setKey(new ServicePathKey(pathId));
219 serviceChainBuilder.setServicePath(Collections.singletonList(servicePathBuilder.build()));
220 return serviceChainBuilder.build();
223 static RenderedServicePath createRenderedPath(final ServiceFunctionPath sfp, final TenantId tenantId,
224 final DataBroker dataBroker) {
225 RenderedServicePath renderedServicePath;
226 // Try to read existing RSP
227 final RspName rspName = generateRspName(sfp, tenantId);
228 renderedServicePath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
229 if (renderedServicePath != null) {
230 return renderedServicePath;
232 LOG.info("Rendered service path with name {} not found, creating a new one ..", rspName.getValue());
233 final CreateRenderedPathInput input = new CreateRenderedPathInputBuilder()
234 .setParentServiceFunctionPath(sfp.getName().getValue())
235 .setName(rspName.getValue())
236 .setSymmetric(sfp.isSymmetric())
238 renderedServicePath = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, input);
239 LOG.info("Rendered service path {} created", rspName.getValue());
240 checkSfcRspStatus(rspName, dataBroker);
241 return renderedServicePath;
244 static RenderedServicePath createSymmetricRenderedPath(final ServiceFunctionPath sfp, final RenderedServicePath rsp,
245 final TenantId tenantId, final DataBroker dataBroker) {
246 RenderedServicePath reversedRenderedPath;
247 // Try to read existing RSP
248 final RspName rspName = generateReversedRspName(sfp, tenantId);
249 reversedRenderedPath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
250 if (reversedRenderedPath != null) {
251 return reversedRenderedPath;
253 LOG.info("Reversed rendered service path with name {} not found, creating a new one ..", rspName.getValue());
254 reversedRenderedPath = SfcProviderRenderedPathAPI.createReverseRenderedServicePathEntry(rsp);
255 LOG.info("Rendered service path {} created", rspName.getValue());
256 checkSfcRspStatus(rspName, dataBroker);
257 return reversedRenderedPath;
261 * Method checks up, whether a {@link Local} Service Function Forwarder is present on device or not.
263 * @param mountpoint used to access specific device
264 * @return true if Local Forwarder is present, false otherwise
266 private static boolean checkLocalForwarderPresence(DataBroker mountpoint) {
267 InstanceIdentifier<Local> localSffIid = InstanceIdentifier.builder(Native.class)
268 .child(ServiceChain.class)
269 .child(org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServiceFunctionForwarder.class)
270 .child(Local.class).build();
272 java.util.Optional<ReadOnlyTransaction> optionalTransaction =
273 NetconfTransactionCreator.netconfReadOnlyTransaction(mountpoint);
274 if (!optionalTransaction.isPresent()) {
275 LOG.warn("Failed to create transaction, mountpoint: {}", mountpoint);
278 ReadOnlyTransaction transaction = optionalTransaction.get();
279 CheckedFuture<Optional<Local>, ReadFailedException> submitFuture =
280 transaction.read(LogicalDatastoreType.CONFIGURATION,
282 Optional<Local> optionalLocalSff = submitFuture.checkedGet();
283 transaction.close(); // Release lock
284 return optionalLocalSff.isPresent();
285 } catch (ReadFailedException e) {
286 LOG.warn("Read transaction failed to {} ", e);
287 } catch (Exception e) {
288 LOG.error("Failed to .. {}", e.getMessage());
294 * Method checks up, if some {@link ServicePath} is present on device.
296 * @param mountpoint used to access specific device
297 * @return true if service chain does not exist, is null or does not contain any service path. False otherwise
299 public static boolean checkServicePathPresence(DataBroker mountpoint) {
300 InstanceIdentifier<ServiceChain> serviceChainIid = InstanceIdentifier.builder(Native.class)
301 .child(ServiceChain.class).build();
302 java.util.Optional<ReadOnlyTransaction> optionalTransaction =
303 NetconfTransactionCreator.netconfReadOnlyTransaction(mountpoint);
304 if (!optionalTransaction.isPresent()) {
305 LOG.warn("Failed to create transaction, mountpoint: {}", mountpoint);
308 ReadOnlyTransaction transaction = optionalTransaction.get();
309 CheckedFuture<Optional<ServiceChain>, ReadFailedException> submitFuture = transaction.read(LogicalDatastoreType.CONFIGURATION,
312 Optional<ServiceChain> optionalServiceChain = submitFuture.checkedGet();
313 if (optionalServiceChain.isPresent()) {
314 ServiceChain chain = optionalServiceChain.get();
315 return chain == null || chain.getServicePath() == null || chain.getServicePath().isEmpty();
319 } catch (ReadFailedException e) {
320 LOG.warn("Read transaction failed to {} ", e);
321 } catch (Exception e) {
322 LOG.error("Failed to .. {}", e.getMessage());
327 static ServiceFunctionPath findServiceFunctionPath(final SfcName chainName) {
328 final ServiceFunctionPaths allPaths = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
329 for (ServiceFunctionPath serviceFunctionPath : allPaths.getServiceFunctionPath()) {
330 if (serviceFunctionPath.getServiceChainName().equals(chainName)) {
331 return serviceFunctionPath;
337 private static RspName generateRspName(final ServiceFunctionPath serviceFunctionPath, final TenantId tenantId) {
338 return new RspName(serviceFunctionPath.getName().getValue() + tenantId.getValue() + RSP_SUFFIX);
341 private static RspName generateReversedRspName(final ServiceFunctionPath serviceFunctionPath, final TenantId tenantId) {
342 return new RspName(serviceFunctionPath.getName().getValue() + tenantId.getValue() + RSP_REVERSED_SUFFIX);
345 private static <T> Supplier<Boolean> createNegativePathWithLogSupplier(final T value, final Consumer<T> logCommand) {
348 logCommand.accept(value);
353 static boolean setSfcPart(final ServiceFunctionPath serviceFunctionPath, final RenderedServicePath renderedServicePath,
354 final RenderedServicePath reversedRenderedServicePath, PolicyWriter policyWriter) {
355 if (!checkLocalForwarderPresence(policyWriter.getCurrentMountpoint())) {
356 appendLocalSff(policyWriter);
358 LOG.info("Local forwarder for node {} is already created", policyWriter.getCurrentNodeId());
360 boolean outcome = true;
362 final java.util.Optional<RenderedServicePath> renderedServicePathSafe = java.util.Optional.ofNullable(renderedServicePath);
363 if (renderedServicePathSafe.isPresent()) {
364 if (renderedServicePath.getRenderedServicePathHop() != null
365 && !renderedServicePath.getRenderedServicePathHop().isEmpty()) {
366 if (!resolveRenderedServicePath(renderedServicePath, policyWriter)) {
371 LOG.warn("Rendered service path {} does not contain any hop",
372 renderedServicePathSafe.map(RenderedServicePath::getName).map(RspName::getValue).orElse("n/a"));
377 LOG.warn("Rendered service path is null");
380 if (serviceFunctionPath.isSymmetric()) {
382 final java.util.Optional<RenderedServicePath> reversedRenderedServicePathSafe = java.util.Optional.ofNullable(reversedRenderedServicePath);
383 if (reversedRenderedServicePathSafe.isPresent()) {
384 if (reversedRenderedServicePath.getRenderedServicePathHop() != null
385 && !reversedRenderedServicePath.getRenderedServicePathHop().isEmpty()) {
386 if (!resolveRenderedServicePath(reversedRenderedServicePath, policyWriter)) {
390 LOG.warn("Rendered service path {} does not contain any hop",
391 reversedRenderedServicePathSafe.map(RenderedServicePath::getName).map(RspName::getValue).orElse("n/a"));
395 LOG.warn("Reversed rendered service path is null");
402 private static boolean resolveRenderedServicePath(final RenderedServicePath renderedServicePath, PolicyWriter policyWriter) {
403 final RenderedServicePathHop firstHop = renderedServicePath.getRenderedServicePathHop().get(0);
404 if (firstHop == null) {
407 final SffName sffName = firstHop.getServiceFunctionForwarder();
411 // If classifier node is also forwarder, first entry in service path has to point to first service function
414 // If first hop Sff is on different node, first service path entry has to point to that specific service
415 // forwarder (Remote case)
417 final java.util.Optional<ServiceFunctionForwarder> serviceFunctionForwarder = java.util.Optional.ofNullable(
418 SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(sffName));
419 return serviceFunctionForwarder.map(sff -> java.util.Optional.ofNullable(sff.getIpMgmtAddress())
420 .map(IpAddress::getIpv4Address)
421 .map((ipv4Address) -> ipv4Address.getValue())
422 .map(addressValue -> {
423 // Set up choice. If remote, this choice is overwritten
424 final ServiceTypeChoice serviceTypeChoice;
425 if (!addressValue.equals(policyWriter.getManagementIpAddress())) {
426 final ServiceFfNameBuilder remoteSffBuilder = new ServiceFfNameBuilder();
427 remoteSffBuilder.setName(sffName.getValue())
428 .setKey(new ServiceFfNameKey(sffName.getValue()))
429 .setIp(new IpBuilder().setAddress(new Ipv4Address(addressValue)).build());
430 policyWriter.cache(remoteSffBuilder.build());
431 serviceTypeChoice = forwarderTypeChoice(sffName.getValue());
433 serviceTypeChoice = functionTypeChoice(firstHop.getServiceFunctionName().getValue());
437 final List<Services> services = new ArrayList<>();
438 final ServicesBuilder servicesBuilder = new ServicesBuilder();
439 servicesBuilder.setServiceIndexId(renderedServicePath.getStartingIndex())
440 .setServiceTypeChoice(serviceTypeChoice);
441 services.add(servicesBuilder.build());
442 final List<ServicePath> servicePaths = new ArrayList<>();
443 final ServicePathBuilder servicePathBuilder = new ServicePathBuilder();
444 servicePathBuilder.setKey(new ServicePathKey(renderedServicePath.getPathId()))
445 .setServicePathId(renderedServicePath.getPathId())
446 .setConfigServiceChainPathMode(new ConfigServiceChainPathModeBuilder()
447 .setServiceIndex(new ServiceIndexBuilder()
448 .setServices(services).build()).build());
449 servicePaths.add(servicePathBuilder.build());
450 final ServiceChainBuilder chainBuilder = new ServiceChainBuilder();
451 chainBuilder.setServicePath(servicePaths);
452 final ServiceChain serviceChain = chainBuilder.build();
453 policyWriter.cache(serviceChain);
456 }).orElseGet(createNegativePathWithLogSupplier(sffName.getValue(),
457 (value) -> LOG.error("Cannot create remote forwarder, SFF {} does not contain management ip address",
460 ).orElseGet(createNegativePathWithLogSupplier(sffName.getValue(),
461 (value) -> LOG.error("Sff with name {} does not exist", value))
465 private static void appendLocalSff(final PolicyWriter policyWriter) {
466 final LocalBuilder localSffBuilder = new LocalBuilder();
467 localSffBuilder.setIp(new IpBuilder().setAddress(new Ipv4Address(policyWriter.getManagementIpAddress()))
469 policyWriter.cache(localSffBuilder.build());
472 static ServiceTypeChoice forwarderTypeChoice(final String forwarderName) {
473 final ServiceFunctionForwarderBuilder sffBuilder = new ServiceFunctionForwarderBuilder();
474 sffBuilder.setServiceFunctionForwarder(forwarderName);
475 return sffBuilder.build();
478 static ServiceTypeChoice functionTypeChoice(final String functionName) {
479 final ServiceFunctionBuilder sfBuilder = new ServiceFunctionBuilder();
480 sfBuilder.setServiceFunction(functionName);
481 return sfBuilder.build();
484 private static void checkSfcRspStatus(final RspName rspName, final DataBroker dataBroker) {
485 /** TODO A better way to do this is to register listener and wait for notification than using hardcoded timeout
486 * with Thread.sleep(). Example in class BridgeDomainManagerImpl
488 ConfiguredRenderedPath renderedPath = null;
489 LOG.info("Waiting for SFC to configure path {} ...", rspName.getValue());
497 } catch (InterruptedException e) {
498 LOG.error("Thread interrupted while waiting ... {} ", e);
500 // Read actual status
501 final InstanceIdentifier<ConfiguredRenderedPath> statusIid = InstanceIdentifier.builder(RendererPathStates.class)
502 .child(RendererPathState.class, new RendererPathStateKey(new RendererName("ios-xe-renderer")))
503 .child(ConfiguredRenderedPaths.class)
504 .child(ConfiguredRenderedPath.class, new ConfiguredRenderedPathKey(rspName)).build();
505 final java.util.Optional<ReadWriteTransaction> optionalTransaction =
506 NetconfTransactionCreator.netconfReadWriteTransaction(dataBroker);
507 if (!optionalTransaction.isPresent()) {
508 LOG.warn("Failed to create transaction, mountpoint: {}", dataBroker);
511 ReadWriteTransaction transaction = optionalTransaction.get();
513 final CheckedFuture<Optional<ConfiguredRenderedPath>, ReadFailedException> submitFuture =
514 transaction.read(LogicalDatastoreType.OPERATIONAL, statusIid);
515 final Optional<ConfiguredRenderedPath> optionalPath = submitFuture.checkedGet();
516 if (optionalPath.isPresent()) {
517 renderedPath = optionalPath.get();
519 } catch (ReadFailedException e) {
520 LOG.warn("Failed while read rendered path status ... {} ", e.getMessage());
522 if (renderedPath == null || renderedPath.getPathStatus() == null ||
523 renderedPath.getPathStatus().equals(ConfiguredRenderedPath.PathStatus.InProgress)) {
524 LOG.info("Still waiting for SFC ... ");
525 } else if (renderedPath.getPathStatus().equals(ConfiguredRenderedPath.PathStatus.Failure)) {
526 LOG.warn("SFC failed to configure rsp");
527 } else if (renderedPath.getPathStatus().equals(ConfiguredRenderedPath.PathStatus.Success)) {
528 LOG.info("RSP {} configured by SFC", rspName.getValue());
530 Thread.sleep(5000); // Just for sure, maybe will be safe to remove this
531 } catch (InterruptedException e) {
532 LOG.error("Thread interrupted while waiting ... {} ", e);
537 while (attempt <= 6);
538 LOG.warn("Maximum number of attempts reached");