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 static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyManagerImpl.ActionCase;
12 import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil.ActionInDirection;
13 import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil.createClassMap;
14 import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil.createPolicyMapEntry;
15 import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil.createSecurityGroupMatch;
16 import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil.generateClassMapName;
17 import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil.getTenantId;
18 import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction.In;
19 import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction.Out;
20 import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation.CONSUMER;
21 import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation.PROVIDER;
23 import javax.annotation.Nonnull;
24 import javax.annotation.Nullable;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.List;
30 import java.util.function.Consumer;
31 import java.util.function.Supplier;
32 import com.google.common.annotations.VisibleForTesting;
33 import com.google.common.base.Optional;
34 import com.google.common.util.concurrent.CheckedFuture;
35 import com.google.common.util.concurrent.Futures;
36 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
37 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
38 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
39 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
40 import org.opendaylight.groupbasedpolicy.api.sf.ChainActionDefinition;
41 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyConfigurationContext;
42 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyManagerImpl;
43 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.NetconfTransactionCreator;
44 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.PolicyWriterUtil;
45 import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
46 import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
47 import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
48 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.RendererPathStates;
49 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.RendererPathState;
50 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.RendererPathStateKey;
51 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.renderer.path.state.ConfiguredRenderedPaths;
52 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.renderer.path.state.configured.rendered.paths.ConfiguredRenderedPath;
53 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.renderer.path.state.configured.rendered.paths.ConfiguredRenderedPathKey;
54 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RendererName;
55 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName;
56 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfcName;
57 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName;
58 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput;
59 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
60 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
61 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
62 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.SffDataPlaneLocator;
63 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.sff.data.plane.locator.DataPlaneLocator;
64 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
65 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
66 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
67 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.LocatorType;
68 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.locator.type.Ip;
69 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
70 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
71 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMap;
72 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChain;
73 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChainBuilder;
74 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native._class.map.Match;
75 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.config.service.chain.grouping.IpBuilder;
76 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.Class;
77 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePath;
78 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathBuilder;
79 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathKey;
80 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfName;
81 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameBuilder;
82 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameKey;
83 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.ConfigServiceChainPathModeBuilder;
84 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.ServiceIndexBuilder;
85 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.Services;
86 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.ServicesBuilder;
87 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.services.ServiceTypeChoice;
88 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;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.RuleName;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.unconfigured.rule.groups.unconfigured.rule.group.UnconfiguredResolvedRuleBuilder;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpoint;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.actions.Action;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
98 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
99 import org.slf4j.Logger;
100 import org.slf4j.LoggerFactory;
102 public class ServiceChainingUtil {
104 private static final Logger LOG = LoggerFactory.getLogger(ServiceChainingUtil.class);
105 private static final String RSP_SUFFIX = "-gbp-rsp";
106 private static final String RSP_REVERSED_SUFFIX = "-gbp-rsp-Reverse";
107 private static long timeout = 5000L;
110 * According to provided action, this method gets service function path and collects all info about participation
111 * and orientation of path. According to path symmetricity, participation and direction, one of these cases happens:
112 * 1. Path is asymmetric, and it starts in this classifier (specified by context) - direct chain is created
113 * 2. Path is asymmetric, and it starts in classifier on opposite side of the chain - skipped
114 * 3. Path is symmetric, and it starts in this classifier - direct chain is created
115 * 2. Path is symmetric, and it starts in classifier on opposite side of the chain - reversed path is created
117 * Behaviour is correct also in case when "this" and "opposite" classifier is the same
119 * @param peerEndpoint - peer endpoint, used to generate status and access to tenant ID
120 * @param sourceSgt - security group tag of source endpoint
121 * @param destinationSgt - security group tag of destination endpoint
122 * @param actionMap - contains all info to evaluate correct chain orientation according to endpoint participation
123 * @param context - contains policy-map location and status info
124 * @param dataBroker - to access odl datastore
126 static void newChainAction(final PeerEndpoint peerEndpoint, final Sgt sourceSgt,
127 final Sgt destinationSgt, final Map<PolicyManagerImpl.ActionCase, ActionInDirection> actionMap,
128 final PolicyConfigurationContext context, final DataBroker dataBroker) {
129 final ActionInDirection actionInDirection = actionMap.get(ActionCase.CHAIN);
130 if (actionInDirection == null) {
133 context.setCurrentUnconfiguredRule(new UnconfiguredResolvedRuleBuilder()
134 .setRuleName(new RuleName(actionInDirection.getRuleName())).build());
135 // Rule action + orientation
136 final Action action = actionInDirection.getAction();
137 final EndpointPolicyParticipation participation = actionInDirection.getParticipation();
138 final Direction direction = actionInDirection.getDirection();
139 // Get service function path
140 final ServiceFunctionPath servicePath = ServiceChainingUtil.findServicePathFromParameterValues(action.getParameterValue());
141 if (servicePath == null || servicePath.getName() == null) {
142 final String info = String.format("service-path not found (sourceSgt=%s, destinationSgt=%s)",
143 sourceSgt, destinationSgt);
144 context.appendUnconfiguredRendererEP(StatusUtil.assembleNotConfigurableRendererEPForPeer(context, peerEndpoint, info));
147 final TenantId tenantId = PolicyManagerUtil.getTenantId(peerEndpoint);
148 if (tenantId == null) {
149 final String info = String.format("tenant-id not found (sourceSgt=%s, destinationSgt=%s)",
150 sourceSgt, destinationSgt);
151 context.appendUnconfiguredRendererEP(StatusUtil.assembleNotConfigurableRendererEPForPeer(context, peerEndpoint, info));
154 boolean sfcPartSuccessful = true;
155 // Creates direct path in corresponding direction
156 if ((participation.equals(PROVIDER) && direction.equals(Out)) ||
157 (participation.equals(CONSUMER) && direction.equals(In))) {
158 final RenderedServicePath renderedServicePath = ServiceChainingUtil.resolveRenderedServicePath(servicePath,
159 tenantId, dataBroker, sourceSgt, destinationSgt, context);
160 sfcPartSuccessful = resolveRemoteSfcComponents(renderedServicePath, context);
161 // Creates reversed path if symmetric
162 } else if (servicePath.isSymmetric()) {
163 final RenderedServicePath renderedServicePath =
164 ServiceChainingUtil.resolveReversedRenderedServicePath(servicePath, tenantId, dataBroker, sourceSgt,
165 destinationSgt, context);
166 sfcPartSuccessful = resolveRemoteSfcComponents(renderedServicePath, context);
168 if (!sfcPartSuccessful) {
169 final String info = String.format("failed during sfc-part execution (sourceSgt=%s, destinationSgt=%s)",
170 sourceSgt, destinationSgt);
171 context.appendUnconfiguredRendererEP(StatusUtil.assembleNotConfigurableRendererEPForPeer(context,
172 peerEndpoint, info));
177 * According to service function path and direction, creates appropriate rendered service path name {@link RspName}
178 * and starts appropriate method which removes policy for resolved endpoint pair
180 * @param peerEndpoint - contains info about tenant ID
181 * @param sourceSgt - security group tag of source endpoint
182 * @param destinationSgt - security group tag of destination endpoint
183 * @param actionMap - contains all info to evaluate correct chain orientation according to endpoint participation
184 * @param context - contains policy-map location and status info
186 static void resolveRemovedChainAction(final PeerEndpoint peerEndpoint, final Sgt sourceSgt, final Sgt destinationSgt,
187 final Map<ActionCase, ActionInDirection> actionMap, final PolicyConfigurationContext context) {
188 final ActionInDirection actionInDirection = actionMap.get(ActionCase.CHAIN);
189 final Action action = actionInDirection.getAction();
190 final EndpointPolicyParticipation participation = actionInDirection.getParticipation();
191 final Direction direction = actionInDirection.getDirection();
192 final ServiceFunctionPath servicePath = ServiceChainingUtil.findServicePathFromParameterValues(action.getParameterValue());
193 if (servicePath == null || servicePath.getName() == null) {
196 final TenantId tenantId = getTenantId(peerEndpoint);
197 if (tenantId == null) {
201 if ((participation.equals(PROVIDER) && direction.equals(Out)) ||
202 (participation.equals(CONSUMER) && direction.equals(In))) {
203 final RspName rspName = generateRspName(servicePath, tenantId);
204 resolveRemovedRenderedServicePath(rspName, sourceSgt, destinationSgt, context);
206 } else if (servicePath.isSymmetric()) {
207 final RspName rspName = generateReversedRspName(servicePath, tenantId);
208 resolveRemovedRenderedServicePath(rspName, sourceSgt, destinationSgt, context);
213 * Service-path (netconf) is created on every netconf device, which contains service function belonging to specific
214 * chain. Classifier has to be able to reach first service function forwarder in order to send packet to chain. If
215 * first service function forwarder is present on the same node as classifier, service-path entry should be already
216 * present (created by IOS-XE renderer in SFC) also with appropriate remote SFF if necessary. If first SFF is on
217 * different node (remote classifier), classifier has to create it's own service-path entry with remote SFF.
219 * @param renderedServicePath - path classifier has to reach
220 * @param context - contains policy-map location and status info
221 * @return true if everything went good, false otherwise
223 public static boolean resolveRemoteSfcComponents(final RenderedServicePath renderedServicePath,
224 final PolicyConfigurationContext context) {
225 final PolicyManagerImpl.PolicyMapLocation location = context.getPolicyMapLocation();
226 final ServiceFunctionForwarder forwarder = getFirstHopSff(renderedServicePath);
227 if (forwarder == null) {
230 final SffName sffName = forwarder.getName();
231 if (forwarder.getSffDataPlaneLocator() == null || forwarder.getSffDataPlaneLocator().isEmpty()) {
232 LOG.warn("Service function forwarder {} does not contain data plane locator", sffName.getValue());
235 // TODO only first dpl resolved
236 final SffDataPlaneLocator sffDataPlaneLocator = forwarder.getSffDataPlaneLocator().get(0);
237 final DataPlaneLocator dataPlaneLocator = sffDataPlaneLocator.getDataPlaneLocator();
238 final LocatorType locatorType = dataPlaneLocator.getLocatorType();
239 if (locatorType != null && locatorType instanceof Ip) {
240 final IpAddress remoteForwarderIpAddress = (((Ip) locatorType).getIp());
241 if (remoteForwarderIpAddress == null || remoteForwarderIpAddress.getIpv4Address() == null) {
242 LOG.warn("Service function forwarder {} data plane locator does not contain ip address", sffName.getValue());
245 final String remoteForwarderStringIp = remoteForwarderIpAddress.getIpv4Address().getValue();
246 final java.util.Optional<IpAddress> optionalIpMgmtAddress = java.util.Optional.ofNullable(forwarder.getIpMgmtAddress());
248 return optionalIpMgmtAddress.map(IpAddress::getIpv4Address)
249 .map(Ipv4Address::getValue)
250 .map(addressValue -> {
251 final ServiceTypeChoice serviceTypeChoice;
252 if (!addressValue.equals(location.getManagementIpAddress())) {
254 final ServiceFfNameBuilder remoteSffBuilder = new ServiceFfNameBuilder();
255 remoteSffBuilder.setName(sffName.getValue())
256 .setKey(new ServiceFfNameKey(sffName.getValue()))
257 .setIp(new IpBuilder().setAddress(new Ipv4Address(remoteForwarderStringIp)).build());
258 boolean rsResult = PolicyWriterUtil.writeRemote(remoteSffBuilder.build(), location);
259 context.setFutureResult(Futures.immediateCheckedFuture(rsResult));
260 serviceTypeChoice = createForwarderTypeChoice(sffName.getValue());
262 final List<Services> services = new ArrayList<>();
263 final ServicesBuilder servicesBuilder = new ServicesBuilder();
264 servicesBuilder.setServiceIndexId(renderedServicePath.getStartingIndex())
265 .setServiceTypeChoice(serviceTypeChoice);
266 services.add(servicesBuilder.build());
267 final List<ServicePath> servicePaths = new ArrayList<>();
268 final ServicePathBuilder servicePathBuilder = new ServicePathBuilder();
269 servicePathBuilder.setKey(new ServicePathKey(renderedServicePath.getPathId()))
270 .setServicePathId(renderedServicePath.getPathId())
271 .setConfigServiceChainPathMode(new ConfigServiceChainPathModeBuilder()
272 .setServiceIndex(new ServiceIndexBuilder()
273 .setServices(services).build()).build());
274 servicePaths.add(servicePathBuilder.build());
275 final ServiceChainBuilder chainBuilder = new ServiceChainBuilder();
276 chainBuilder.setServicePath(servicePaths);
277 final ServiceChain serviceChain = chainBuilder.build();
278 boolean scResult = PolicyWriterUtil.writeServicePath(serviceChain, location);
279 context.setFutureResult(Futures.immediateCheckedFuture(scResult));
282 }).orElseGet(createNegativePathWithLogSupplier(sffName.getValue(),
283 (value) -> LOG.error("Cannot create remote forwarder, SFF {} does not contain management ip address",
291 * Investigates provided parameter values and derives service chain name. This name is used to find service function
294 * @param params - list of parameters
295 * @return - service function path if found, null if provided parameters does not correspond with any chain or there
296 * is no service function path defined by that chain
299 static ServiceFunctionPath findServicePathFromParameterValues(final List<ParameterValue> params) {
300 if (params == null || params.isEmpty()) {
301 LOG.error("Cannot found service path, parameter value is null");
304 final Map<String, Object> paramsMap = new HashMap<>();
305 for (ParameterValue value : params) {
306 if (value.getName() == null)
308 if (value.getIntValue() != null) {
309 paramsMap.put(value.getName().getValue(), value.getIntValue());
310 } else if (value.getStringValue() != null) {
311 paramsMap.put(value.getName().getValue(), value.getStringValue());
314 String chainName = null;
315 for (String name : paramsMap.keySet()) {
316 if (name.equals(ChainActionDefinition.SFC_CHAIN_NAME)) {
317 chainName = (String) paramsMap.get(name);
320 if (chainName == null) {
321 LOG.error("Cannot found service path, chain name is null");
324 final ServiceFunctionPath serviceFunctionPath = findServiceFunctionPathFromServiceChainName(new SfcName(chainName));
325 if (serviceFunctionPath == null) {
326 LOG.error("Service function path not found for name {}", chainName);
329 return serviceFunctionPath;
332 static ServiceFunctionPath findServiceFunctionPathFromServiceChainName(@Nonnull final SfcName chainName) {
333 final ServiceFunctionPaths allPaths = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
334 if (allPaths == null || allPaths.getServiceFunctionPath() == null || allPaths.getServiceFunctionPath().isEmpty()) {
337 for (ServiceFunctionPath serviceFunctionPath : allPaths.getServiceFunctionPath()) {
338 if (chainName.equals(serviceFunctionPath.getServiceChainName())) {
339 return serviceFunctionPath;
346 * Creates {@link RenderedServicePath} if not exist. If created, ios-xe renderer in SFC is invoked, so this method
347 * has to wait till SFC part is done to prevent transaction collisions in {@link this#checkRspManagerStatus(RspName,
348 * DataBroker)}. If this operation is successful, class-map {@link ClassMap} and entry in policy-map {@link Class}
351 * @param sfp - path used to create RSP
352 * @param tenantId - used to generate RSP name according to GBP standards
353 * @param dataBroker - data provider to access odl controller
354 * @param sourceSgt - source security group tag
355 * @param destinationSgt - destination security group tag
356 * @param context - contains policy-map location and status info
357 * @return read/created RSP
359 static RenderedServicePath resolveRenderedServicePath(final ServiceFunctionPath sfp, final TenantId tenantId,
360 final DataBroker dataBroker, final Sgt sourceSgt, final Sgt destinationSgt,
361 final PolicyConfigurationContext context) {
362 // Get rendered service path
363 final RspName rspName = generateRspName(sfp, tenantId);
364 RenderedServicePath renderedServicePath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
365 if (renderedServicePath == null) {
366 LOG.info("Rendered service path with name {} not found, creating a new one ..", rspName.getValue());
367 final CreateRenderedPathInput input = new CreateRenderedPathInputBuilder()
368 .setParentServiceFunctionPath(sfp.getName().getValue())
369 .setName(rspName.getValue())
370 .setSymmetric(sfp.isSymmetric())
372 renderedServicePath = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, input);
373 LOG.info("Rendered service path {} created", rspName.getValue());
374 checkRspManagerStatus(rspName, dataBroker);
376 // Create class-map and policy-map entry
377 final String classMapName = generateClassMapName(sourceSgt.getValue(), destinationSgt.getValue());
378 final Match match = createSecurityGroupMatch(sourceSgt.getValue(), destinationSgt.getValue());
379 final ClassMap classMap = createClassMap(classMapName, match);
380 final Class policyMapEntry = createPolicyMapEntry(classMapName, renderedServicePath, ActionCase.CHAIN);
381 boolean cmResult = PolicyWriterUtil.writeClassMap(classMap, context.getPolicyMapLocation());
382 context.setFutureResult(Futures.immediateCheckedFuture(cmResult));
383 boolean pmeResult = PolicyWriterUtil.writePolicyMapEntry(policyMapEntry, context.getPolicyMapLocation());
384 context.setFutureResult(Futures.immediateCheckedFuture(pmeResult));
385 return renderedServicePath;
389 * Creates reversed {@link RenderedServicePath} if not exist. To be successful, direct path has to exist.
390 * If created, ios-xe renderer in SFC is invoked, so this method has to wait till SFC part is done to prevent
391 * transaction collisions. If this operation is successful, class-map {@link ClassMap} and entry in policy-map
392 * {@link Class} is written
394 * @param sfp - path used to create RSP
395 * @param tenantId - used to generate RSP name according to GBP standards
396 * @param dataBroker - data provider to access odl controller
397 * @param sourceSgt - source security group tag
398 * @param destinationSgt - destination security group tag
399 * @param context - contains policy-map location and status info
400 * @return read/created RSP
402 public static RenderedServicePath resolveReversedRenderedServicePath(final ServiceFunctionPath sfp, final TenantId tenantId,
403 final DataBroker dataBroker, final Sgt sourceSgt,
404 final Sgt destinationSgt, final PolicyConfigurationContext context) {
405 // Get rendered service path
406 final RspName rspName = generateRspName(sfp, tenantId);
407 RenderedServicePath renderedServicePath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
408 if (renderedServicePath == null) {
409 LOG.info("Rendered service path with name {} not found, creating a new one ..", rspName.getValue());
410 final CreateRenderedPathInput input = new CreateRenderedPathInputBuilder()
411 .setParentServiceFunctionPath(sfp.getName().getValue())
412 .setName(rspName.getValue())
413 .setSymmetric(sfp.isSymmetric())
415 renderedServicePath = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, input);
416 LOG.info("Rendered service path {} created", rspName.getValue());
417 checkRspManagerStatus(rspName, dataBroker);
419 // Get reversed rendered service path
420 final RspName reversedRspName = generateReversedRspName(sfp, tenantId);
421 RenderedServicePath reversedRenderedPath = SfcProviderRenderedPathAPI.readRenderedServicePath(reversedRspName);
422 if (reversedRenderedPath == null) {
423 LOG.info("Reversed rendered service path with name {} not found, creating a new one ..", reversedRspName.getValue());
424 reversedRenderedPath = SfcProviderRenderedPathAPI.createReverseRenderedServicePathEntry(renderedServicePath);
425 LOG.info("Rendered service path {} created", reversedRspName.getValue());
426 checkRspManagerStatus(reversedRspName, dataBroker);
428 // Create class-map and policy-map entry
429 final String classMapName = generateClassMapName(sourceSgt.getValue(), destinationSgt.getValue());
430 final Match match = createSecurityGroupMatch(sourceSgt.getValue(), destinationSgt.getValue());
431 final ClassMap classMap = createClassMap(classMapName, match);
432 final Class policyMapEntry = createPolicyMapEntry(classMapName, renderedServicePath, ActionCase.CHAIN);
433 boolean cmResult = PolicyWriterUtil.writeClassMap(classMap, context.getPolicyMapLocation());
434 context.setFutureResult(Futures.immediateCheckedFuture(cmResult));
435 boolean pmeResult = PolicyWriterUtil.writePolicyMapEntry(policyMapEntry, context.getPolicyMapLocation());
436 context.setFutureResult(Futures.immediateCheckedFuture(pmeResult));
437 resolveRemoteSfcComponents(renderedServicePath, context);
438 return reversedRenderedPath;
442 * Removes all policy setup created according to rendered service path.
444 * @param rspName - rendered service path name
445 * @param sourceSgt - source security group tag
446 * @param destinationSgt - destination security group tag
447 * @param context - context with policy-map location
449 private static void resolveRemovedRenderedServicePath(final RspName rspName, final Sgt sourceSgt, final Sgt destinationSgt,
450 final PolicyConfigurationContext context) {
451 final String classMapName = PolicyManagerUtil.generateClassMapName(sourceSgt.getValue(), destinationSgt.getValue());
452 final ClassMap classMap = PolicyManagerUtil.createClassMap(classMapName, null);
453 final Class policyMapEntry = PolicyManagerUtil.createPolicyMapEntry(classMapName, null, PolicyManagerImpl.ActionCase.CHAIN);
454 PolicyWriterUtil.removePolicyMapEntry(policyMapEntry, context.getPolicyMapLocation());
455 PolicyWriterUtil.removeClassMap(classMap, context.getPolicyMapLocation());
456 final RenderedServicePath renderedServicePath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
457 final ServiceFunctionForwarder firstHopSff = getFirstHopSff(renderedServicePath);
458 if (firstHopSff != null && firstHopSff.getIpMgmtAddress() != null &&
459 firstHopSff.getIpMgmtAddress().getIpv4Address() != null) {
460 final String sffMgmtIpValue = firstHopSff.getIpMgmtAddress().getIpv4Address().getValue();
461 if (!sffMgmtIpValue.equals(context.getPolicyMapLocation().getManagementIpAddress())) {
462 // Remove service chain and remote forwarder
463 final ServiceChain serviceChain = createServiceChain(renderedServicePath);
464 final ServiceFfName remoteForwarder = createRemoteForwarder(firstHopSff);
465 PolicyWriterUtil.removeServicePath(serviceChain, context.getPolicyMapLocation());
466 PolicyWriterUtil.removeRemote(remoteForwarder, context.getPolicyMapLocation());
471 static ServiceFfName createRemoteForwarder(ServiceFunctionForwarder firstHopSff) {
472 final ServiceFfNameBuilder serviceFfNameBuilder = new ServiceFfNameBuilder();
473 serviceFfNameBuilder.setName(firstHopSff.getName().getValue());
474 return serviceFfNameBuilder.build();
477 private static ServiceTypeChoice createForwarderTypeChoice(final String forwarderName) {
478 final ServiceFunctionForwarderBuilder sffBuilder = new ServiceFunctionForwarderBuilder();
479 sffBuilder.setServiceFunctionForwarder(forwarderName);
480 return sffBuilder.build();
484 * Creates service-chain with name/key only, using rendered service path id. This object contains no data, it is used
485 * to create instance identifier when appropriate service-chain is removed from particular device
487 * @param renderedServicePath - it's path id is used as a identifier
488 * @return service-chain object with id
490 private static ServiceChain createServiceChain(final RenderedServicePath renderedServicePath) {
491 final Long pathId = renderedServicePath.getPathId();
492 final ServicePathBuilder servicePathBuilder = new ServicePathBuilder();
493 final ServiceChainBuilder serviceChainBuilder = new ServiceChainBuilder();
494 servicePathBuilder.setServicePathId(pathId)
495 .setKey(new ServicePathKey(pathId));
496 serviceChainBuilder.setServicePath(Collections.singletonList(servicePathBuilder.build()));
497 return serviceChainBuilder.build();
500 private static <T> Supplier<Boolean> createNegativePathWithLogSupplier(final T value, final Consumer<T> logCommand) {
503 logCommand.accept(value);
508 private static ServiceFunctionForwarder getFirstHopSff(RenderedServicePath renderedServicePath) {
509 if (renderedServicePath == null || renderedServicePath.getRenderedServicePathHop() == null ||
510 renderedServicePath.getRenderedServicePathHop().isEmpty()) {
513 final RenderedServicePathHop firstHop = renderedServicePath.getRenderedServicePathHop().get(0);
514 final SffName firstHopSff = firstHop.getServiceFunctionForwarder();
515 if (firstHopSff == null) {
518 return SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(firstHopSff);
521 private static RspName generateRspName(final ServiceFunctionPath serviceFunctionPath, final TenantId tenantId) {
522 return new RspName(serviceFunctionPath.getName().getValue() + "-" + tenantId.getValue() + RSP_SUFFIX);
525 private static RspName generateReversedRspName(final ServiceFunctionPath serviceFunctionPath, final TenantId tenantId) {
526 return new RspName(serviceFunctionPath.getName().getValue() + "-" + tenantId.getValue() + RSP_REVERSED_SUFFIX);
529 private static void checkRspManagerStatus(final RspName rspName, final DataBroker dataBroker) {
530 // TODO A better way to do this is to register listener and wait for notification than using hardcoded timeout
531 // with Thread.sleep(). Example in class BridgeDomainManagerImpl
532 ConfiguredRenderedPath renderedPath = null;
533 LOG.debug("Waiting for SFC to configure path {} ...", rspName.getValue());
540 Thread.sleep(timeout);
541 } catch (InterruptedException e) {
542 LOG.error("Thread interrupted while waiting ... {} ", e);
544 // Read actual status
545 final InstanceIdentifier<ConfiguredRenderedPath> statusIid = InstanceIdentifier.builder(RendererPathStates.class)
546 .child(RendererPathState.class, new RendererPathStateKey(new RendererName("ios-xe-renderer")))
547 .child(ConfiguredRenderedPaths.class)
548 .child(ConfiguredRenderedPath.class, new ConfiguredRenderedPathKey(rspName)).build();
549 final java.util.Optional<ReadWriteTransaction> optionalTransaction =
550 NetconfTransactionCreator.netconfReadWriteTransaction(dataBroker);
551 if (!optionalTransaction.isPresent()) {
552 LOG.warn("Failed to create transaction, mountpoint: {}", dataBroker);
555 ReadWriteTransaction transaction = optionalTransaction.get();
557 final CheckedFuture<Optional<ConfiguredRenderedPath>, ReadFailedException> submitFuture =
558 transaction.read(LogicalDatastoreType.OPERATIONAL, statusIid);
559 final Optional<ConfiguredRenderedPath> optionalPath = submitFuture.checkedGet();
560 if (optionalPath.isPresent()) {
561 renderedPath = optionalPath.get();
563 } catch (ReadFailedException e) {
564 LOG.warn("Failed while read rendered path status ... {} ", e.getMessage());
566 if (renderedPath == null || renderedPath.getPathStatus() == null ||
567 renderedPath.getPathStatus().equals(ConfiguredRenderedPath.PathStatus.InProgress)) {
568 LOG.info("Still waiting for SFC ... ");
569 } else if (renderedPath.getPathStatus().equals(ConfiguredRenderedPath.PathStatus.Failure)) {
570 LOG.warn("SFC failed to configure rsp");
571 } else if (renderedPath.getPathStatus().equals(ConfiguredRenderedPath.PathStatus.Success)) {
572 LOG.debug("RSP {} configured by SFC", rspName.getValue());
574 Thread.sleep(timeout); // Just for sure, maybe will be safe to remove this
575 } catch (InterruptedException e) {
576 LOG.error("Thread interrupted while waiting ... {} ", e);
581 while (attempt <= 6);
582 LOG.warn("Maximum number of attempts reached");
586 * Only for test purposes
588 * @param value - set actual timeout value
591 public static void setTimeout(long value) {