ios-xe now uses sgt augments
[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 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;
15
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21
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;
77
78 import com.google.common.base.Preconditions;
79 import com.google.common.util.concurrent.Futures;
80 import com.google.common.util.concurrent.ListenableFuture;
81
82 public class PolicyManagerImpl implements PolicyManager {
83
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<>();
89
90     public enum ActionCase { ALLOW, CHAIN }
91
92
93     public PolicyManagerImpl(final DataBroker dataBroker) {
94         this.dataBroker = Preconditions.checkNotNull(dataBroker);
95         mapper = new PolicyMapper(dataBroker);
96     }
97
98     @Override
99     public ListenableFuture<Boolean> syncPolicy(final Configuration dataBefore, final Configuration dataAfter) {
100         // CREATE
101         for (RendererEndpoint rendererEndpoint : dataAfter.getRendererEndpoints().getRendererEndpoint()) {
102             // Get mountpoint
103             if (dataAfter.getEndpoints() == null) {
104                 continue;
105             }
106             DataBroker mountpoint = getAbsoluteLocationMountpoint(rendererEndpoint, dataAfter.getEndpoints()
107                     .getAddressEndpointWithLocation());
108             if (mountpoint == null) {
109                 continue;
110             }
111             // Initialize appropriate writer
112             PolicyWriter policyWriter;
113             if (perDeviceWriterCache.containsKey(mountpoint)) {
114                 policyWriter = perDeviceWriterCache.get(mountpoint);
115             } else {
116                 policyWriter = new PolicyWriter(mountpoint);
117                 perDeviceWriterCache.put(mountpoint, policyWriter);
118             }
119             // Peer Endpoint
120             for (PeerEndpointWithPolicy peerEndpoint : rendererEndpoint.getPeerEndpointWithPolicy()) {
121                 // Sgt Tags
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) {
127                     continue;
128                 }
129                 syncPolicyEntities(sourceSgt, destinationSgt, policyWriter, dataAfter, peerEndpoint);
130             }
131         }
132         // Flush
133         perDeviceWriterCache.values().forEach(PolicyWriter::commitToDatastore);
134         perDeviceWriterCache.clear();
135
136         return Futures.immediateFuture(true);
137     }
138
139     private void syncPolicyEntities(final Sgt sourceSgt, final Sgt destinationSgt, PolicyWriter policyWriter,
140                                    final Configuration dataAfter, final PeerEndpointWithPolicy peerEndpoint) {
141         // Class map
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);
146
147         Map<ActionCase, Action> actionMap = getActionInDirection(dataAfter, peerEndpoint);
148         if (actionMap == null || actionMap.isEmpty()) {
149             return;
150         }
151         // Policy map entry
152         List<Class> policyMapEntries = new ArrayList<>();
153         if (actionMap.containsKey(ActionCase.ALLOW)) {
154             policyMapEntries = resolveAllowAction();
155         }
156         if (actionMap.containsKey(ActionCase.CHAIN)) {
157             policyMapEntries = resolveChainAction(peerEndpoint, sourceSgt, destinationSgt, actionMap, classMapName);
158         }
159         policyWriter.write(policyMapEntries);
160     }
161
162     private Sgt findSgtTag(final AddressEndpointKey endpointKey,
163                             final List<AddressEndpointWithLocation> endpointsWithLocation) {
164         if (endpointKey == null || endpointsWithLocation == null) {
165             return null;
166         }
167         AddressEndpointWithLocation endpointWithLocation = RendererPolicyUtil.lookupEndpoint(endpointKey,
168                 endpointsWithLocation);
169         AddressEndpointWithLocationAug augmentation = endpointWithLocation.getAugmentation(AddressEndpointWithLocationAug.class);
170         if (augmentation == null) {
171             return null;
172         }
173
174         return augmentation.getSgt();
175     }
176
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) {
184             return null;
185         }
186         TenantId tenantId = getTenantId(peerEndpoint);
187         if (tenantId == null) {
188             return  null;
189         }
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));
198         }
199         return entries;
200     }
201
202     private List<Class> resolveAllowAction() {
203         List<Class> entries = new ArrayList<>();
204         entries.add(mapper.createPolicyEntry(policyMapName, null, ActionCase.ALLOW));
205         return entries;
206     }
207
208     private DataBroker getAbsoluteLocationMountpoint(final RendererEndpoint endpoint,
209                                                      final List<AddressEndpointWithLocation> endpointsWithLocation) {
210         if (endpoint == null || endpointsWithLocation == null) {
211             return null;
212         }
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());
221             return null;
222         }
223         InstanceIdentifier mountPointId = location.getExternalNodeMountPoint();
224         return NodeManager.getDataBrokerFromCache(mountPointId);
225     }
226
227     private String generateClassMapName(Integer sourceTag, Integer destinationTag) {
228         return "srcTag" + sourceTag + "_dstTag" + destinationTag;
229     }
230
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) {
239                 continue;
240             }
241
242             for (ResolvedRule resolvedRule : ruleGroup.getResolvedRule()) {
243                 if (resolvedRule == null) {
244                     continue;
245                 }
246                 if (resolvedRule.getClassifier() == null || resolvedRule.getAction() == null) {
247                     continue;
248                 }
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);
255                 }
256             }
257         }
258         if (rulesInDirection.isEmpty()) {
259             return null; // TODO define drop?
260         }
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);
270                     return result;
271                 } else if (actionDefinitionId.equals(ChainActionDefinition.ID)) {
272                     result.put(ActionCase.CHAIN, action);
273                     return result;
274                 }
275             }
276         }
277         return null;
278     }
279
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))
287                 continue;
288             if (!ruleGroup.getContractId().equals(contractId)) {
289                 continue;
290             }
291             if (ruleGroup.getSubjectName().equals(subjectName)) {
292                 return ruleGroup;
293             }
294         }
295         return null;
296     }
297
298     private TenantId getTenantId(PeerEndpointWithPolicy peer) {
299         for (RuleGroupWithRendererEndpointParticipation ruleGroup :
300                 peer.getRuleGroupWithRendererEndpointParticipation()) {
301             if (ruleGroup.getTenantId() != null) {
302                 return ruleGroup.getTenantId();
303             }
304         }
305         return null;
306     }
307
308
309     private void resolveFirstSffOnClassifier(final Ipv4Address nodeIpAddress,
310                                              final Set<RenderedServicePath> firstHops) {
311         // Local forwarder
312         LocalBuilder localSffBuilder = new LocalBuilder();
313         localSffBuilder.setIp(new IpBuilder().setAddress(nodeIpAddress).build());
314
315         // TODO add sff to writer
316
317         for (RenderedServicePath renderedPath : firstHops) {
318             // Remote forwarder
319             RenderedServicePathHop firstRenderedPathHop = renderedPath.getRenderedServicePathHop().get(0);
320             SffName sffName = firstRenderedPathHop.getServiceFunctionForwarder();
321
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();
326
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
332
333             // Service chain
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
351         }
352     }
353
354     private ServiceTypeChoice sffTypeChoice(String forwarderName) {
355         ServiceFunctionForwarderBuilder sffBuilder = new ServiceFunctionForwarderBuilder();
356         sffBuilder.setServiceFunctionForwarder(forwarderName);
357         return sffBuilder.build();
358     }
359
360     @Override
361     public void close() {
362         //NOOP
363     }
364 }