ios-xe renderer - policy manager + mapper
[groupbasedpolicy.git] / renderers / ios-xe / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ios_xe_provider / impl / manager / PolicyManagerImpl.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager;
10
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.groupbasedpolicy.api.sf.AllowActionDefinition;
16 import org.opendaylight.groupbasedpolicy.api.sf.ChainActionDefinition;
17 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.api.cache.DSTreeBasedCache;
18 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.api.manager.PolicyManager;
19 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.cache.EpPolicyTemplateCacheKey;
20 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil;
21 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyWriter;
22 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.RendererPolicyUtil;
23 import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
24 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName;
25 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
26 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
27 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
29 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMap;
30 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChain;
31 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChainBuilder;
32 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native._class.map.Match;
33 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.Class;
34 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePath;
35 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathBuilder;
36 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathKey;
37 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.LocalBuilder;
38 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameBuilder;
39 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameKey;
40 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.ConfigServiceChainPathModeBuilder;
41 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.ServiceIndexBuilder;
42 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.Services;
43 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.ServicesBuilder;
44 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.services.ServiceTypeChoice;
45 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;
46 import org.opendaylight.yang.gen.v1.urn.ios.rev160308.config.service.chain.grouping.IpBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.AddressEndpointKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocation;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.LocationType;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.rule.group.with.renderer.endpoint.participation.RuleGroupWithRendererEndpointParticipation;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.Configuration;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpoint;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpointWithPolicy;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.rule.groups.RuleGroup;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.actions.Action;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.classifiers.Classifier;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.resolved.rules.ResolvedRule;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgt;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
68 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71
72 import java.util.ArrayList;
73 import java.util.HashMap;
74 import java.util.List;
75 import java.util.Map;
76 import java.util.Set;
77
78 import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction.In;
79 import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction.Out;
80 import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation.CONSUMER;
81 import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation.PROVIDER;
82
83 public class PolicyManagerImpl implements PolicyManager {
84
85     private static final Logger LOG = LoggerFactory.getLogger(PolicyMapper.class);
86     private final DataBroker dataBroker;
87     private DSTreeBasedCache<EndpointPolicyTemplateBySgt, EpPolicyTemplateCacheKey, Sgt> epPolicyCache;
88     private final PolicyMapper mapper;
89     private final String policyMapName = "service-chains";
90     private Map<DataBroker, PolicyWriter> perDeviceWriterCache = new HashMap<>();
91
92     public enum ActionCase {ALLOW, CHAIN}
93
94
95     public PolicyManagerImpl(final DataBroker dataBroker,
96                              final DSTreeBasedCache<EndpointPolicyTemplateBySgt, EpPolicyTemplateCacheKey, Sgt> epPolicyCache) {
97         this.dataBroker = Preconditions.checkNotNull(dataBroker);
98         this.epPolicyCache = Preconditions.checkNotNull(epPolicyCache);
99         mapper = new PolicyMapper(dataBroker);
100     }
101
102     @Override
103     public ListenableFuture<Boolean> syncPolicy(final Configuration dataAfter, final Configuration dataBefore) {
104         // CREATE
105         for (RendererEndpoint rendererEndpoint : dataAfter.getRendererEndpoints().getRendererEndpoint()) {
106             // Get mountpoint
107             if (dataAfter.getEndpoints() == null) {
108                 continue;
109             }
110             DataBroker mountpoint = getAbsoluteLocationMountpoint(rendererEndpoint, dataAfter.getEndpoints()
111                     .getAddressEndpointWithLocation());
112             if (mountpoint == null) {
113                 continue;
114             }
115             // Initialize appropriate writer
116             PolicyWriter policyWriter;
117             if (perDeviceWriterCache.containsKey(mountpoint)) {
118                 policyWriter = perDeviceWriterCache.get(mountpoint);
119             } else {
120                 policyWriter = new PolicyWriter(mountpoint);
121                 perDeviceWriterCache.put(mountpoint, policyWriter);
122             }
123             // Peer Endpoint
124             for (PeerEndpointWithPolicy peerEndpoint : rendererEndpoint.getPeerEndpointWithPolicy()) {
125                 // Sgt Tags
126                 final Sgt sourceSgt = findSgtTag(rendererEndpoint, dataAfter.getEndpoints()
127                         .getAddressEndpointWithLocation());
128                 final Sgt destinationSgt = findSgtTag(peerEndpoint, dataAfter.getEndpoints()
129                         .getAddressEndpointWithLocation());
130                 if (sourceSgt == null || destinationSgt == null) {
131                     continue;
132                 }
133                 syncPolicyEntities(sourceSgt, destinationSgt, policyWriter, dataAfter, peerEndpoint);
134             }
135         }
136         // Flush
137         perDeviceWriterCache.values().forEach(PolicyWriter::commitToDatastore);
138         perDeviceWriterCache.clear();
139
140         return Futures.immediateFuture(true);
141     }
142
143     private void syncPolicyEntities(final Sgt sourceSgt, final Sgt destinationSgt, PolicyWriter policyWriter,
144                                    final Configuration dataAfter, final PeerEndpointWithPolicy peerEndpoint) {
145         // Class map
146         String classMapName = generateClassMapName(sourceSgt.getValue(), destinationSgt.getValue());
147         Match match = mapper.createSecurityGroupMatch(sourceSgt.getValue(), destinationSgt.getValue());
148         ClassMap classMap = mapper.createClassMap(classMapName, match);
149         policyWriter.write(classMap);
150
151         Map<ActionCase, Action> actionMap = getActionInDirection(dataAfter, peerEndpoint);
152         if (actionMap == null || actionMap.isEmpty()) {
153             return;
154         }
155         // Policy map entry
156         List<Class> policyMapEntries = new ArrayList<>();
157         if (actionMap.containsKey(ActionCase.ALLOW)) {
158             policyMapEntries = resolveAllowAction();
159         }
160         if (actionMap.containsKey(ActionCase.CHAIN)) {
161             policyMapEntries = resolveChainAction(peerEndpoint, sourceSgt, destinationSgt, actionMap, classMapName);
162         }
163         policyWriter.write(policyMapEntries);
164     }
165
166     private Sgt findSgtTag(final AddressEndpointKey endpointKey,
167                             final List<AddressEndpointWithLocation> endpointsWithLocation) {
168         if (endpointKey == null || endpointsWithLocation == null) {
169             return null;
170         }
171         AddressEndpointWithLocation endpointWithLocation = RendererPolicyUtil.lookupEndpoint(endpointKey,
172                 endpointsWithLocation);
173         return epPolicyCache.lookupValue(new EpPolicyTemplateCacheKey(endpointWithLocation));
174     }
175
176     private List<Class> resolveChainAction(final PeerEndpointWithPolicy peerEndpoint, final Sgt sourceSgt,
177                                            final Sgt destinationSgt, final Map<ActionCase, Action> actionMap,
178                                            final String classMapName) {
179         List<Class> entries = new ArrayList<>();
180         final Action action = actionMap.get(ActionCase.CHAIN);
181         ServiceFunctionPath servicePath = PolicyManagerUtil.getServicePath(action.getParameterValue());
182         if (servicePath == null) {
183             return null;
184         }
185         TenantId tenantId = getTenantId(peerEndpoint);
186         if (tenantId == null) {
187             return  null;
188         }
189         RenderedServicePath renderedPath = PolicyManagerUtil.createRenderedPath(servicePath, tenantId);
190         entries.add(mapper.createPolicyEntry(classMapName, renderedPath, ActionCase.CHAIN));
191         if (servicePath.isSymmetric()) {
192             // symmetric path is in opposite direction. Roles of renderer and peer endpoint will invert
193             RenderedServicePath symmetricPath = PolicyManagerUtil
194                     .createSymmetricRenderedPath(servicePath, renderedPath, tenantId);
195             String oppositeClassMapName = generateClassMapName(destinationSgt.getValue(), sourceSgt.getValue());
196             entries.add(mapper.createPolicyEntry(oppositeClassMapName, symmetricPath, ActionCase.CHAIN));
197         }
198         return entries;
199     }
200
201     private List<Class> resolveAllowAction() {
202         List<Class> entries = new ArrayList<>();
203         entries.add(mapper.createPolicyEntry(policyMapName, null, ActionCase.ALLOW));
204         return entries;
205     }
206
207     private DataBroker getAbsoluteLocationMountpoint(final RendererEndpoint endpoint,
208                                                      final List<AddressEndpointWithLocation> endpointsWithLocation) {
209         if (endpoint == null || endpointsWithLocation == null) {
210             return null;
211         }
212         AddressEndpointWithLocation endpointWithLocation = RendererPolicyUtil.lookupEndpoint(endpoint,
213                 endpointsWithLocation);
214         final AbsoluteLocation absoluteLocation = endpointWithLocation.getAbsoluteLocation();
215         final LocationType locationType = absoluteLocation.getLocationType();
216         ExternalLocationCase location = (ExternalLocationCase) locationType;
217         if (location == null) {
218             LOG.warn("Endpoint {} does not contain info about external location",
219                     endpointWithLocation.getKey().toString());
220             return null;
221         }
222         InstanceIdentifier mountPointId = location.getExternalNodeMountPoint();
223         return NodeManager.getDataBrokerFromCache(mountPointId);
224     }
225
226     private String generateClassMapName(Integer sourceTag, Integer destinationTag) {
227         return "srcTag" + sourceTag + "_dstTag" + destinationTag;
228     }
229
230     private Map<ActionCase, Action> getActionInDirection(Configuration data, PeerEndpointWithPolicy peer) {
231         List<ResolvedRule> rulesInDirection = new ArrayList<>();
232         // Find all rules in desired direction
233         for (RuleGroupWithRendererEndpointParticipation ruleGroupKey :
234                 peer.getRuleGroupWithRendererEndpointParticipation()) {
235             EndpointPolicyParticipation participation = ruleGroupKey.getRendererEndpointParticipation();
236             RuleGroup ruleGroup = findRuleGroup(data, ruleGroupKey);
237             if (ruleGroup == null || ruleGroup.getResolvedRule() == null) {
238                 continue;
239             }
240
241             for (ResolvedRule resolvedRule : ruleGroup.getResolvedRule()) {
242                 if (resolvedRule == null) {
243                     continue;
244                 }
245                 if (resolvedRule.getClassifier() == null || resolvedRule.getAction() == null) {
246                     continue;
247                 }
248                 // TODO only first Classifier used
249                 Classifier classifier = resolvedRule.getClassifier().get(0);
250                 HasDirection.Direction direction = classifier.getDirection();
251                 if ((participation.equals(PROVIDER) && direction.equals(Out)) ||
252                         (participation.equals(CONSUMER) && direction.equals(In))) {
253                     rulesInDirection.add(resolvedRule);
254                 }
255             }
256         }
257         if (rulesInDirection.isEmpty()) {
258             return null; // TODO define drop?
259         }
260         // TODO use only first rule with ActionDefinitionID for now
261         Map<ActionCase, Action> result = new HashMap<>();
262         for (ResolvedRule resolvedRule : rulesInDirection) {
263             // TODO only first action used for now
264             Action action = resolvedRule.getAction().get(0);
265             if (action.getActionDefinitionId() != null) {
266                 ActionDefinitionId actionDefinitionId = action.getActionDefinitionId();
267                 if (actionDefinitionId.equals(AllowActionDefinition.ID)) {
268                     result.put(ActionCase.ALLOW, action);
269                     return result;
270                 } else if (actionDefinitionId.equals(ChainActionDefinition.ID)) {
271                     result.put(ActionCase.CHAIN, action);
272                     return result;
273                 }
274             }
275         }
276         return null;
277     }
278
279     private RuleGroup findRuleGroup(final Configuration data,
280                                     final RuleGroupWithRendererEndpointParticipation ruleGroupWithParticipation) {
281         final TenantId tenantId = ruleGroupWithParticipation.getTenantId();
282         final ContractId contractId = ruleGroupWithParticipation.getContractId();
283         final SubjectName subjectName = ruleGroupWithParticipation.getSubjectName();
284         for (RuleGroup ruleGroup : data.getRuleGroups().getRuleGroup()) {
285             if (!ruleGroup.getTenantId().equals(tenantId))
286                 continue;
287             if (!ruleGroup.getContractId().equals(contractId)) {
288                 continue;
289             }
290             if (ruleGroup.getSubjectName().equals(subjectName)) {
291                 return ruleGroup;
292             }
293         }
294         return null;
295     }
296
297     private TenantId getTenantId(PeerEndpointWithPolicy peer) {
298         for (RuleGroupWithRendererEndpointParticipation ruleGroup :
299                 peer.getRuleGroupWithRendererEndpointParticipation()) {
300             if (ruleGroup.getTenantId() != null) {
301                 return ruleGroup.getTenantId();
302             }
303         }
304         return null;
305     }
306
307
308     private void resolveFirstSffOnClassifier(final Ipv4Address nodeIpAddress,
309                                              final Set<RenderedServicePath> firstHops) {
310         // Local forwarder
311         LocalBuilder localSffBuilder = new LocalBuilder();
312         localSffBuilder.setIp(new IpBuilder().setAddress(nodeIpAddress).build());
313
314         // TODO add sff to writer
315
316         for (RenderedServicePath renderedPath : firstHops) {
317             // Remote forwarder
318             RenderedServicePathHop firstRenderedPathHop = renderedPath.getRenderedServicePathHop().get(0);
319             SffName sffName = firstRenderedPathHop.getServiceFunctionForwarder();
320
321             // Remap sff and its management ip address
322             org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder serviceFunctionForwarder =
323                     SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(sffName);
324             String sffMgmtIpAddress = serviceFunctionForwarder.getIpMgmtAddress().getIpv4Address().getValue();
325
326             ServiceFfNameBuilder remoteSffBuilder = new ServiceFfNameBuilder();
327             remoteSffBuilder.setName(sffName.getValue())
328                     .setKey(new ServiceFfNameKey(sffName.getValue()))
329                     .setIp(new IpBuilder().setAddress(new Ipv4Address(sffMgmtIpAddress)).build());
330             // TODO add sff to writer
331
332             // Service chain
333             List<Services> services = new ArrayList<>();
334             ServiceTypeChoice serviceTypeChoice = sffTypeChoice(sffName.getValue());
335             ServicesBuilder servicesBuilder = new ServicesBuilder();
336             servicesBuilder.setServiceIndexId(renderedPath.getStartingIndex())
337                     .setServiceTypeChoice(serviceTypeChoice);
338             List<ServicePath> servicePaths = new ArrayList<>();
339             ServicePathBuilder servicePathBuilder = new ServicePathBuilder();
340             servicePathBuilder.setKey(new ServicePathKey(renderedPath.getPathId()))
341                     .setServicePathId(renderedPath.getPathId())
342                     .setConfigServiceChainPathMode(new ConfigServiceChainPathModeBuilder()
343                             .setServiceIndex(new ServiceIndexBuilder()
344                                     .setServices(services).build()).build());
345             servicePaths.add(servicePathBuilder.build());
346             ServiceChainBuilder chainBuilder = new ServiceChainBuilder();
347             chainBuilder.setServicePath(servicePaths);
348             ServiceChain serviceChain = chainBuilder.build();
349             // TODO add service-chain to writer
350         }
351     }
352
353     private ServiceTypeChoice sffTypeChoice(String forwarderName) {
354         ServiceFunctionForwarderBuilder sffBuilder = new ServiceFunctionForwarderBuilder();
355         sffBuilder.setServiceFunctionForwarder(forwarderName);
356         return sffBuilder.build();
357     }
358
359     @Override
360     public void close() {
361         //NOOP
362     }
363 }