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.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction.In;
12 import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction.Out;
13 import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation.CONSUMER;
14 import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation.PROVIDER;
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.List;
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.groupbasedpolicy.api.sf.AllowActionDefinition;
24 import org.opendaylight.groupbasedpolicy.api.sf.ChainActionDefinition;
25 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.api.manager.PolicyManager;
26 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil;
27 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyWriter;
28 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.RendererPolicyUtil;
29 import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
30 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName;
31 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
32 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
33 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
35 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMap;
36 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChain;
37 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChainBuilder;
38 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native._class.map.Match;
39 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.Class;
40 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePath;
41 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathBuilder;
42 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathKey;
43 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.LocalBuilder;
44 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameBuilder;
45 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameKey;
46 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.ConfigServiceChainPathModeBuilder;
47 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.ServiceIndexBuilder;
48 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.Services;
49 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.ServicesBuilder;
50 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.services.ServiceTypeChoice;
51 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.services.service.type.choice.ServiceFunctionForwarderBuilder;
52 import org.opendaylight.yang.gen.v1.urn.ios.rev160308.config.service.chain.grouping.IpBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.AddressEndpointKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocation;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.LocationType;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.rule.group.with.renderer.endpoint.participation.RuleGroupWithRendererEndpointParticipation;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.Configuration;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpoint;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpointWithPolicy;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.rule.groups.RuleGroup;
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.groupbasedpolicy.resolved.policy.rev150828.has.classifiers.Classifier;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.resolved.rules.ResolvedRule;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.AddressEndpointWithLocationAug;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
74 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
78 import com.google.common.base.Preconditions;
79 import com.google.common.util.concurrent.Futures;
80 import com.google.common.util.concurrent.ListenableFuture;
82 public class PolicyManagerImpl implements PolicyManager {
84 private static final Logger LOG = LoggerFactory.getLogger(PolicyMapper.class);
85 private final DataBroker dataBroker;
86 private final PolicyMapper mapper;
87 private final String policyMapName = "service-chains";
88 private Map<DataBroker, PolicyWriter> perDeviceWriterCache = new HashMap<>();
90 public enum ActionCase { ALLOW, CHAIN }
93 public PolicyManagerImpl(final DataBroker dataBroker) {
94 this.dataBroker = Preconditions.checkNotNull(dataBroker);
95 mapper = new PolicyMapper(dataBroker);
99 public ListenableFuture<Boolean> syncPolicy(final Configuration dataBefore, final Configuration dataAfter) {
101 for (RendererEndpoint rendererEndpoint : dataAfter.getRendererEndpoints().getRendererEndpoint()) {
103 if (dataAfter.getEndpoints() == null) {
106 DataBroker mountpoint = getAbsoluteLocationMountpoint(rendererEndpoint, dataAfter.getEndpoints()
107 .getAddressEndpointWithLocation());
108 if (mountpoint == null) {
111 // Initialize appropriate writer
112 PolicyWriter policyWriter;
113 if (perDeviceWriterCache.containsKey(mountpoint)) {
114 policyWriter = perDeviceWriterCache.get(mountpoint);
116 policyWriter = new PolicyWriter(mountpoint);
117 perDeviceWriterCache.put(mountpoint, policyWriter);
120 for (PeerEndpointWithPolicy peerEndpoint : rendererEndpoint.getPeerEndpointWithPolicy()) {
122 final Sgt sourceSgt = findSgtTag(rendererEndpoint, dataAfter.getEndpoints()
123 .getAddressEndpointWithLocation());
124 final Sgt destinationSgt = findSgtTag(peerEndpoint, dataAfter.getEndpoints()
125 .getAddressEndpointWithLocation());
126 if (sourceSgt == null || destinationSgt == null) {
129 syncPolicyEntities(sourceSgt, destinationSgt, policyWriter, dataAfter, peerEndpoint);
133 perDeviceWriterCache.values().forEach(PolicyWriter::commitToDatastore);
134 perDeviceWriterCache.clear();
136 return Futures.immediateFuture(true);
139 private void syncPolicyEntities(final Sgt sourceSgt, final Sgt destinationSgt, PolicyWriter policyWriter,
140 final Configuration dataAfter, final PeerEndpointWithPolicy peerEndpoint) {
142 String classMapName = generateClassMapName(sourceSgt.getValue(), destinationSgt.getValue());
143 Match match = mapper.createSecurityGroupMatch(sourceSgt.getValue(), destinationSgt.getValue());
144 ClassMap classMap = mapper.createClassMap(classMapName, match);
145 policyWriter.write(classMap);
147 Map<ActionCase, Action> actionMap = getActionInDirection(dataAfter, peerEndpoint);
148 if (actionMap == null || actionMap.isEmpty()) {
152 List<Class> policyMapEntries = new ArrayList<>();
153 if (actionMap.containsKey(ActionCase.ALLOW)) {
154 policyMapEntries = resolveAllowAction();
156 if (actionMap.containsKey(ActionCase.CHAIN)) {
157 policyMapEntries = resolveChainAction(peerEndpoint, sourceSgt, destinationSgt, actionMap, classMapName);
159 policyWriter.write(policyMapEntries);
162 private Sgt findSgtTag(final AddressEndpointKey endpointKey,
163 final List<AddressEndpointWithLocation> endpointsWithLocation) {
164 if (endpointKey == null || endpointsWithLocation == null) {
167 AddressEndpointWithLocation endpointWithLocation = RendererPolicyUtil.lookupEndpoint(endpointKey,
168 endpointsWithLocation);
169 AddressEndpointWithLocationAug augmentation = endpointWithLocation.getAugmentation(AddressEndpointWithLocationAug.class);
170 if (augmentation == null) {
174 return augmentation.getSgt();
177 private List<Class> resolveChainAction(final PeerEndpointWithPolicy peerEndpoint, final Sgt sourceSgt,
178 final Sgt destinationSgt, final Map<ActionCase, Action> actionMap,
179 final String classMapName) {
180 List<Class> entries = new ArrayList<>();
181 final Action action = actionMap.get(ActionCase.CHAIN);
182 ServiceFunctionPath servicePath = PolicyManagerUtil.getServicePath(action.getParameterValue());
183 if (servicePath == null) {
186 TenantId tenantId = getTenantId(peerEndpoint);
187 if (tenantId == null) {
190 RenderedServicePath renderedPath = PolicyManagerUtil.createRenderedPath(servicePath, tenantId);
191 entries.add(mapper.createPolicyEntry(classMapName, renderedPath, ActionCase.CHAIN));
192 if (servicePath.isSymmetric()) {
193 // symmetric path is in opposite direction. Roles of renderer and peer endpoint will invert
194 RenderedServicePath symmetricPath = PolicyManagerUtil
195 .createSymmetricRenderedPath(servicePath, renderedPath, tenantId);
196 String oppositeClassMapName = generateClassMapName(destinationSgt.getValue(), sourceSgt.getValue());
197 entries.add(mapper.createPolicyEntry(oppositeClassMapName, symmetricPath, ActionCase.CHAIN));
202 private List<Class> resolveAllowAction() {
203 List<Class> entries = new ArrayList<>();
204 entries.add(mapper.createPolicyEntry(policyMapName, null, ActionCase.ALLOW));
208 private DataBroker getAbsoluteLocationMountpoint(final RendererEndpoint endpoint,
209 final List<AddressEndpointWithLocation> endpointsWithLocation) {
210 if (endpoint == null || endpointsWithLocation == null) {
213 AddressEndpointWithLocation endpointWithLocation = RendererPolicyUtil.lookupEndpoint(endpoint,
214 endpointsWithLocation);
215 final AbsoluteLocation absoluteLocation = endpointWithLocation.getAbsoluteLocation();
216 final LocationType locationType = absoluteLocation.getLocationType();
217 ExternalLocationCase location = (ExternalLocationCase) locationType;
218 if (location == null) {
219 LOG.warn("Endpoint {} does not contain info about external location",
220 endpointWithLocation.getKey().toString());
223 InstanceIdentifier mountPointId = location.getExternalNodeMountPoint();
224 return NodeManager.getDataBrokerFromCache(mountPointId);
227 private String generateClassMapName(Integer sourceTag, Integer destinationTag) {
228 return "srcTag" + sourceTag + "_dstTag" + destinationTag;
231 private Map<ActionCase, Action> getActionInDirection(Configuration data, PeerEndpointWithPolicy peer) {
232 List<ResolvedRule> rulesInDirection = new ArrayList<>();
233 // Find all rules in desired direction
234 for (RuleGroupWithRendererEndpointParticipation ruleGroupKey :
235 peer.getRuleGroupWithRendererEndpointParticipation()) {
236 EndpointPolicyParticipation participation = ruleGroupKey.getRendererEndpointParticipation();
237 RuleGroup ruleGroup = findRuleGroup(data, ruleGroupKey);
238 if (ruleGroup == null || ruleGroup.getResolvedRule() == null) {
242 for (ResolvedRule resolvedRule : ruleGroup.getResolvedRule()) {
243 if (resolvedRule == null) {
246 if (resolvedRule.getClassifier() == null || resolvedRule.getAction() == null) {
249 // TODO only first Classifier used
250 Classifier classifier = resolvedRule.getClassifier().get(0);
251 HasDirection.Direction direction = classifier.getDirection();
252 if ((participation.equals(PROVIDER) && direction.equals(Out)) ||
253 (participation.equals(CONSUMER) && direction.equals(In))) {
254 rulesInDirection.add(resolvedRule);
258 if (rulesInDirection.isEmpty()) {
259 return null; // TODO define drop?
261 // TODO use only first rule with ActionDefinitionID for now
262 Map<ActionCase, Action> result = new HashMap<>();
263 for (ResolvedRule resolvedRule : rulesInDirection) {
264 // TODO only first action used for now
265 Action action = resolvedRule.getAction().get(0);
266 if (action.getActionDefinitionId() != null) {
267 ActionDefinitionId actionDefinitionId = action.getActionDefinitionId();
268 if (actionDefinitionId.equals(AllowActionDefinition.ID)) {
269 result.put(ActionCase.ALLOW, action);
271 } else if (actionDefinitionId.equals(ChainActionDefinition.ID)) {
272 result.put(ActionCase.CHAIN, action);
280 private RuleGroup findRuleGroup(final Configuration data,
281 final RuleGroupWithRendererEndpointParticipation ruleGroupWithParticipation) {
282 final TenantId tenantId = ruleGroupWithParticipation.getTenantId();
283 final ContractId contractId = ruleGroupWithParticipation.getContractId();
284 final SubjectName subjectName = ruleGroupWithParticipation.getSubjectName();
285 for (RuleGroup ruleGroup : data.getRuleGroups().getRuleGroup()) {
286 if (!ruleGroup.getTenantId().equals(tenantId))
288 if (!ruleGroup.getContractId().equals(contractId)) {
291 if (ruleGroup.getSubjectName().equals(subjectName)) {
298 private TenantId getTenantId(PeerEndpointWithPolicy peer) {
299 for (RuleGroupWithRendererEndpointParticipation ruleGroup :
300 peer.getRuleGroupWithRendererEndpointParticipation()) {
301 if (ruleGroup.getTenantId() != null) {
302 return ruleGroup.getTenantId();
309 private void resolveFirstSffOnClassifier(final Ipv4Address nodeIpAddress,
310 final Set<RenderedServicePath> firstHops) {
312 LocalBuilder localSffBuilder = new LocalBuilder();
313 localSffBuilder.setIp(new IpBuilder().setAddress(nodeIpAddress).build());
315 // TODO add sff to writer
317 for (RenderedServicePath renderedPath : firstHops) {
319 RenderedServicePathHop firstRenderedPathHop = renderedPath.getRenderedServicePathHop().get(0);
320 SffName sffName = firstRenderedPathHop.getServiceFunctionForwarder();
322 // Remap sff and its management ip address
323 org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder serviceFunctionForwarder =
324 SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(sffName);
325 String sffMgmtIpAddress = serviceFunctionForwarder.getIpMgmtAddress().getIpv4Address().getValue();
327 ServiceFfNameBuilder remoteSffBuilder = new ServiceFfNameBuilder();
328 remoteSffBuilder.setName(sffName.getValue())
329 .setKey(new ServiceFfNameKey(sffName.getValue()))
330 .setIp(new IpBuilder().setAddress(new Ipv4Address(sffMgmtIpAddress)).build());
331 // TODO add sff to writer
334 List<Services> services = new ArrayList<>();
335 ServiceTypeChoice serviceTypeChoice = sffTypeChoice(sffName.getValue());
336 ServicesBuilder servicesBuilder = new ServicesBuilder();
337 servicesBuilder.setServiceIndexId(renderedPath.getStartingIndex())
338 .setServiceTypeChoice(serviceTypeChoice);
339 List<ServicePath> servicePaths = new ArrayList<>();
340 ServicePathBuilder servicePathBuilder = new ServicePathBuilder();
341 servicePathBuilder.setKey(new ServicePathKey(renderedPath.getPathId()))
342 .setServicePathId(renderedPath.getPathId())
343 .setConfigServiceChainPathMode(new ConfigServiceChainPathModeBuilder()
344 .setServiceIndex(new ServiceIndexBuilder()
345 .setServices(services).build()).build());
346 servicePaths.add(servicePathBuilder.build());
347 ServiceChainBuilder chainBuilder = new ServiceChainBuilder();
348 chainBuilder.setServicePath(servicePaths);
349 ServiceChain serviceChain = chainBuilder.build();
350 // TODO add service-chain to writer
354 private ServiceTypeChoice sffTypeChoice(String forwarderName) {
355 ServiceFunctionForwarderBuilder sffBuilder = new ServiceFunctionForwarderBuilder();
356 sffBuilder.setServiceFunctionForwarder(forwarderName);
357 return sffBuilder.build();
361 public void close() {