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.manager;
11 import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyManagerImpl.DsAction.Create;
12 import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyManagerImpl.DsAction.Delete;
14 import com.google.common.base.Function;
15 import com.google.common.base.Preconditions;
16 import com.google.common.util.concurrent.AsyncFunction;
17 import com.google.common.util.concurrent.CheckedFuture;
18 import com.google.common.util.concurrent.Futures;
19 import com.google.common.util.concurrent.ListenableFuture;
20 import com.google.common.util.concurrent.MoreExecutors;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.Optional;
25 import java.util.concurrent.TimeUnit;
26 import javax.annotation.Nonnull;
27 import javax.annotation.Nullable;
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
32 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.api.manager.PolicyManager;
33 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil;
34 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.RendererPolicyUtil;
35 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.StatusUtil;
36 import org.opendaylight.groupbasedpolicy.sxp.ep.provider.api.EPToSgtMapper;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.Renderers;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.RendererKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicy;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicyBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.Configuration;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.Status;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.StatusBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpoint;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpoint;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.status.UnconfiguredEndpointsBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.IpSgtDistributionService;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.SendIpSgtBindingToPeerInputBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
58 public class PolicyManagerImpl implements PolicyManager {
60 private static final Logger LOG = LoggerFactory.getLogger(PolicyManagerImpl.class);
61 public static final RendererName IOS_XE_RENDERER = new RendererName("ios-xe-renderer");
62 private static final String BASE_POLICY_MAP_NAME = "service-chains-";
63 private final DataBroker dataBroker;
64 private final NodeManager nodeManager;
65 private final EPToSgtMapper epToSgtMapper;
66 private final IpSgtDistributionService ipSgtDistributor;
68 public PolicyManagerImpl(final DataBroker dataBroker,
69 final NodeManager nodeManager, final EPToSgtMapper epToSgtMapper,
70 final IpSgtDistributionService ipSgtDistributor) {
71 this.dataBroker = Preconditions.checkNotNull(dataBroker);
72 this.nodeManager = Preconditions.checkNotNull(nodeManager);
73 this.epToSgtMapper = Preconditions.checkNotNull(epToSgtMapper);
74 this.ipSgtDistributor = Preconditions.checkNotNull(ipSgtDistributor);
79 public ListenableFuture<Boolean> syncPolicy(@Nullable final Configuration dataAfter, @Nullable final Configuration dataBefore,
81 ListenableFuture<Optional<Status>> creationResult;
82 if (dataBefore == null && dataAfter != null) {
83 creationResult = syncEndpoints(dataAfter, Create);
84 } else if (dataBefore != null && dataAfter == null) {
85 creationResult = syncEndpoints(dataBefore, Delete);
87 final ListenableFuture<Optional<Status>> deletionResult = syncEndpoints(dataBefore, Delete);
88 creationResult = Futures.transformAsync(deletionResult, new AsyncFunction<Optional<Status>, Optional<Status>>() {
91 public ListenableFuture<Optional<Status>> apply(@Nonnull Optional<Status> deletionResult) throws Exception {
92 if (deletionResult.isPresent()) {
93 // Wait till task is done. Result is not used, delete case has no status
96 return syncEndpoints(dataAfter, Create);
98 }, MoreExecutors.directExecutor());
100 return Futures.transformAsync(creationResult, new AsyncFunction<Optional<Status>, Boolean>() {
102 public ListenableFuture<Boolean> apply(@Nullable final Optional<Status> statusValue) throws Exception {
103 Preconditions.checkArgument(statusValue != null, "provided status must not be null");
104 return Futures.transform(reportPolicy(version, statusValue), new Function<Void, Boolean>() {
106 public Boolean apply(@Nullable final Void input) {
109 }, MoreExecutors.directExecutor());
111 }, MoreExecutors.directExecutor());
115 * Resolve policy for all endpoint pairs
117 * @param dataAfter - data used while processing
118 * @param action - specifies whether data are intended for creating or removing of configuration
119 * @return status of policy resolution
122 private ListenableFuture<Optional<Status>> syncEndpoints(final Configuration dataAfter, final DsAction action) {
123 if (dataAfter.getRendererEndpoints() == null
124 || dataAfter.getRendererEndpoints().getRendererEndpoint() == null) {
125 LOG.debug("No configuration obtained - skipping");
126 return Futures.immediateFuture(Optional.empty());
128 final PolicyConfigurationContext context = new PolicyConfigurationContext();
130 for (RendererEndpoint rendererEndpoint : dataAfter.getRendererEndpoints().getRendererEndpoint()) {
131 context.setCurrentRendererEP(rendererEndpoint);
133 if (dataAfter.getEndpoints() == null || dataAfter.getEndpoints().getAddressEndpointWithLocation() == null) {
134 final String info = "Renderer-endpoint: missing address-endpoint-with-location";
135 context.appendUnconfiguredRendererEP(StatusUtil.assembleFullyNotConfigurableRendererEP(context, info));
138 final List<AddressEndpointWithLocation> endpointsWithLocation = dataAfter.getEndpoints()
139 .getAddressEndpointWithLocation();
140 final InstanceIdentifier mountpointIid = PolicyManagerUtil.getMountpointIidFromAbsoluteLocation(rendererEndpoint, endpointsWithLocation);
141 final DataBroker mountpoint = nodeManager.getNodeMountPoint(mountpointIid);
142 if (mountpoint == null) {
143 final String info = String.format("No data-broker for mount-point [%s] available", mountpointIid);
144 context.appendUnconfiguredRendererEP(StatusUtil.assembleFullyNotConfigurableRendererEP(context, info));
147 final Optional<String> optionalManagementIpAddress = nodeManager.getNodeManagementIpByMountPointIid(mountpointIid);
148 if (! optionalManagementIpAddress.isPresent()) {
149 final String info = String.format("Can not create policyWriter, managementIpAddress for mountpoint %s is null",
151 context.appendUnconfiguredRendererEP(StatusUtil.assembleFullyNotConfigurableRendererEP(context, info));
154 final String managementIpAddress = optionalManagementIpAddress.get();
155 final String interfaceName = PolicyManagerUtil.getInterfaceNameFromAbsoluteLocation(rendererEndpoint, endpointsWithLocation);
156 final NodeId nodeId = nodeManager.getNodeIdByMountpointIid(mountpointIid);
157 if (interfaceName == null || nodeId == null) {
158 final String info = String.format("Cannot compose policy-map, missing value. Interface: %s, NodeId: %s", interfaceName, nodeId);
159 context.appendUnconfiguredRendererEP(StatusUtil.assembleFullyNotConfigurableRendererEP(context, info));
163 final String policyMapName = BASE_POLICY_MAP_NAME.concat(interfaceName);
164 final PolicyMapLocation policyMapLocation = new PolicyMapLocation(policyMapName, interfaceName, nodeId,
165 managementIpAddress, mountpoint);
166 context.setPolicyMapLocation(policyMapLocation);
168 // TODO: pull timeout for async ops from config
169 final long TIMEOUT = 10;
170 final TimeUnit UNIT = TimeUnit.SECONDS;
172 final SendIpSgtBindingToPeerInputBuilder ipSgtBindings = new SendIpSgtBindingToPeerInputBuilder();
173 ipSgtBindings.setBinding(new ArrayList<>());
175 final Sgt sourceSgt = PolicyManagerUtil.findSgtTag(epToSgtMapper, rendererEndpoint, dataAfter.getEndpoints()
176 .getAddressEndpointWithLocation(), TIMEOUT, UNIT);
177 final AddressEndpointWithLocation sourceEPAddressWithLocation = RendererPolicyUtil.lookupEndpoint(
178 rendererEndpoint, dataAfter.getEndpoints().getAddressEndpointWithLocation());
180 PolicyManagerUtil.createIpSgtBindingItem(sourceSgt, sourceEPAddressWithLocation).ifPresent(ipSgtBindings.getBinding()::add);
183 for (PeerEndpoint peerEndpoint : rendererEndpoint.getPeerEndpoint()) {
184 final Sgt destinationSgt = PolicyManagerUtil.findSgtTag(epToSgtMapper, peerEndpoint, dataAfter.getEndpoints()
185 .getAddressEndpointWithLocation(), TIMEOUT, UNIT);
186 final AddressEndpointWithLocation destinationEPAddressWithLocation = RendererPolicyUtil.lookupEndpoint(
187 peerEndpoint, dataAfter.getEndpoints().getAddressEndpointWithLocation());
188 PolicyManagerUtil.createIpSgtBindingItem(destinationSgt, destinationEPAddressWithLocation)
189 .ifPresent(ipSgtBindings.getBinding()::add);
191 if (sourceSgt == null || destinationSgt == null) {
192 final String info = String.format("Endpoint-policy: missing sgt value(sourceSgt=%s, destinationSgt=%s)",
193 sourceSgt, destinationSgt);
194 context.appendUnconfiguredRendererEP(
195 StatusUtil.assembleNotConfigurableRendererEPForPeer(context, peerEndpoint, info));
198 // Resolve policy between endpoints
199 if (action.equals(Create)) {
200 LOG.debug("Setting up policy between endpoint {}, sgt: {} and peer {}, sgt: {}", rendererEndpoint,
201 sourceSgt, peerEndpoint, destinationSgt);
202 PolicyManagerUtil.syncEndpointPairCreatePolicy(sourceSgt, destinationSgt, context, dataAfter,
203 peerEndpoint, dataBroker);
205 LOG.debug("Removing policy between endpoint {}, sgt: {} and peer {}, sgt: {}", rendererEndpoint,
206 sourceSgt, peerEndpoint, destinationSgt);
207 PolicyManagerUtil.syncEndpointPairRemovePolicy(sourceSgt, destinationSgt, context, dataAfter,
212 ipSgtDistributor.sendIpSgtBindingToPeer(ipSgtBindings.build());
214 final ListenableFuture<List<Boolean>> cumulativeResult = context.getCumulativeResult();
215 return Futures.transform(cumulativeResult, new Function<List<Boolean>, Optional<Status>>() {
218 public Optional<Status> apply(@Nullable final List<Boolean> input) {
219 //TODO: inspect if all booleans are true
221 LOG.trace("considering all submits as successful - otherwise there will be exception");
222 final Status status = new StatusBuilder()
223 .setUnconfiguredEndpoints(new UnconfiguredEndpointsBuilder()
224 .setUnconfiguredRendererEndpoint(context.getUnconfiguredRendererEPBag())
228 return Optional.of(status);
230 }, MoreExecutors.directExecutor());
233 private CheckedFuture<Void, TransactionCommitFailedException> reportPolicy(final long version,
234 @Nonnull final Optional<Status> statusValue) {
235 if (statusValue.isPresent()) {
236 LOG.warn("IOS-XE renderer: operation not successfully completed, check unconfigured policy in operational/renderer:renderers");
238 final ReadWriteTransaction readWriteTransaction = dataBroker.newReadWriteTransaction();
239 final InstanceIdentifier<RendererPolicy> iid = InstanceIdentifier.create(Renderers.class)
240 .child(Renderer.class, new RendererKey(IOS_XE_RENDERER))
241 .child(RendererPolicy.class);
242 final RendererPolicy rendererPolicy = new RendererPolicyBuilder()
244 .setStatus(statusValue.orElse(null))
246 readWriteTransaction.merge(LogicalDatastoreType.OPERATIONAL, iid, rendererPolicy);
247 return readWriteTransaction.submit();
251 public void close() {
255 enum DsAction {Create, Delete}
257 public enum ActionCase {ALLOW, CHAIN}
260 * Wrapper class - contains all necessary information to clearly localize policy-map/interface/node in network
262 public static class PolicyMapLocation {
264 private final String policyMapName;
265 private final String interfaceName;
266 private final NodeId nodeId;
267 private final String managementIpAddress;
268 private final DataBroker mountpoint;
270 public PolicyMapLocation(final String policyMapName, final String interfaceName, final NodeId nodeId,
271 final String managementIpAddress, final DataBroker mountpoint) {
272 this.policyMapName = Preconditions.checkNotNull(policyMapName);
273 this.interfaceName = Preconditions.checkNotNull(interfaceName);
274 this.nodeId = Preconditions.checkNotNull(nodeId);
275 this.managementIpAddress = Preconditions.checkNotNull(managementIpAddress);
276 this.mountpoint = Preconditions.checkNotNull(mountpoint);
279 public String getPolicyMapName() {
280 return policyMapName;
283 public String getInterfaceName() {
284 return interfaceName;
287 public NodeId getNodeId() {
291 public String getManagementIpAddress() {
292 return managementIpAddress;
295 public DataBroker getMountpoint() {