Merge "Resolved policy contracts"
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / policy / VppRendererPolicyManager.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.vpp.policy;
10
11 import java.util.Collection;
12 import java.util.HashSet;
13 import java.util.Map;
14 import java.util.Map.Entry;
15 import java.util.Set;
16 import java.util.stream.Collectors;
17
18 import javax.annotation.Nonnull;
19
20 import org.opendaylight.controller.config.yang.config.vpp_provider.impl.VppRenderer;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.event.NodeOperEvent;
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.event.RendererPolicyConfEvent;
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.KeyFactory;
27 import org.opendaylight.groupbasedpolicy.util.IidFactory;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicy;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicyBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpointKey;
32 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import com.google.common.base.Optional;
39 import com.google.common.base.Preconditions;
40 import com.google.common.collect.HashMultimap;
41 import com.google.common.collect.ImmutableSet;
42 import com.google.common.collect.MapDifference;
43 import com.google.common.collect.MapDifference.ValueDifference;
44 import com.google.common.collect.Maps;
45 import com.google.common.collect.SetMultimap;
46 import com.google.common.collect.Sets;
47 import com.google.common.collect.Sets.SetView;
48 import com.google.common.eventbus.Subscribe;
49 import com.google.common.util.concurrent.FutureCallback;
50 import com.google.common.util.concurrent.Futures;
51
52 public class VppRendererPolicyManager {
53
54     private static final Logger LOG = LoggerFactory.getLogger(VppRendererPolicyManager.class);
55     private final DataBroker dataProvider;
56     private ForwardingManager fwManager;
57
58     public VppRendererPolicyManager(@Nonnull ForwardingManager fwManager, @Nonnull DataBroker dataProvider) {
59         this.fwManager = Preconditions.checkNotNull(fwManager);
60         this.dataProvider = Preconditions.checkNotNull(dataProvider);
61     }
62
63     @Subscribe
64     public void rendererPolicyChanged(RendererPolicyConfEvent event) {
65         RendererPolicyBuilder responseBuilder = new RendererPolicyBuilder();
66         switch (event.getDtoModificationType()) {
67             case CREATED:
68                 LOG.trace("CREATED : {}", event);
69                 responseBuilder.setVersion(event.getAfter().get().getVersion());
70                 rendererPolicyCreated(event.getAfter().get());
71                 break;
72             case UPDATED:
73                 LOG.trace("UPDATED: {}", event);
74                 RendererPolicy rPolicyBefore = event.getBefore().get();
75                 RendererPolicy rPolicyAfter = event.getAfter().get();
76                 responseBuilder.setVersion(rPolicyAfter.getVersion());
77                 if (!isConfigurationChanged(rPolicyBefore, rPolicyAfter)) {
78                     LOG.debug("Configuration is not changed only updating config version from {} to {}",
79                             rPolicyBefore.getVersion(), rPolicyAfter.getVersion());
80                 } else {
81                     // TODO collect unconfigured rules and put them to responseBuilder
82                     rendererPolicyUpdated(rPolicyBefore, rPolicyAfter);
83                 }
84                 break;
85             case DELETED:
86                 LOG.trace("DELETED: {}", event);
87                 responseBuilder.setVersion(event.getBefore().get().getVersion());
88                 rendererPolicyDeleted(event.getBefore().get());
89                 break;
90         }
91         WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
92         RendererPolicy response = responseBuilder.build();
93         wTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.rendererIid(VppRenderer.NAME).child(RendererPolicy.class),
94                 response, true);
95         Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
96
97             @Override
98             public void onSuccess(Void result) {
99                 LOG.debug("Renderer updated renderer policy {}", response);
100             }
101
102             @Override
103             public void onFailure(Throwable t) {
104                 LOG.warn("Renderer DIDN'T update renderer-policy {}", response);
105             }
106         });
107     }
108
109     private boolean isConfigurationChanged(RendererPolicy before, RendererPolicy after) {
110         if (before.getConfiguration() == null && after.getConfiguration() == null) {
111             return false;
112         }
113         return true;
114     }
115
116     private void rendererPolicyUpdated(RendererPolicy rPolicyBefore, RendererPolicy rPolicyAfter) {
117         PolicyContext policyCtxBefore = new PolicyContext(rPolicyBefore);
118         PolicyContext policyCtxAfter = new PolicyContext(rPolicyAfter);
119
120         MapDifference<String, Collection<NodeId>> vppNodesByL2FlDiff =
121                 createDiffForVppNodesByL2Fd(policyCtxBefore, policyCtxAfter);
122         SetMultimap<String, NodeId> removedVppNodesByL2Fd = HashMultimap.create();
123         SetMultimap<String, NodeId> createdVppNodesByL2Fd = HashMultimap.create();
124         for (Entry<String, ValueDifference<Collection<NodeId>>> entry : vppNodesByL2FlDiff.entriesDiffering()
125             .entrySet()) {
126             String bridgeDomain = entry.getKey();
127             Collection<NodeId> beforeNodes = entry.getValue().leftValue();
128             Collection<NodeId> afterNodes = entry.getValue().rightValue();
129             if (beforeNodes != null && afterNodes != null) {
130                 SetView<NodeId> removedNodes = Sets.difference(new HashSet<>(beforeNodes), new HashSet<>(afterNodes));
131                 removedVppNodesByL2Fd.putAll(bridgeDomain, removedNodes);
132                 SetView<NodeId> createdNodes = Sets.difference(new HashSet<>(afterNodes), new HashSet<>(beforeNodes));
133                 createdVppNodesByL2Fd.putAll(bridgeDomain, createdNodes);
134             } else if (beforeNodes != null) {
135                 removedVppNodesByL2Fd.putAll(bridgeDomain, beforeNodes);
136             } else if (afterNodes != null) {
137                 createdVppNodesByL2Fd.putAll(bridgeDomain, afterNodes);
138             }
139         }
140         Map<String, Collection<NodeId>> removedL2Fds = vppNodesByL2FlDiff.entriesOnlyOnLeft();
141         for (Entry<String, Collection<NodeId>> entry : removedL2Fds.entrySet()) {
142             String bridgeDomain = entry.getKey();
143             Collection<NodeId> removedNodes = entry.getValue();
144             if (removedNodes != null) {
145                 removedVppNodesByL2Fd.putAll(bridgeDomain, removedNodes);
146             }
147         }
148         Map<String, Collection<NodeId>> createdL2Fds = vppNodesByL2FlDiff.entriesOnlyOnRight();
149         for (Entry<String, Collection<NodeId>> entry : createdL2Fds.entrySet()) {
150             String bridgeDomain = entry.getKey();
151             Collection<NodeId> createdNodes = entry.getValue();
152             if (createdNodes != null) {
153                 createdVppNodesByL2Fd.putAll(bridgeDomain, createdNodes);
154             }
155         }
156
157         ImmutableSet<RendererEndpointKey> rendEpsBefore = policyCtxBefore.getPolicyTable().rowKeySet();
158         ImmutableSet<RendererEndpointKey> rendEpsAfter = policyCtxAfter.getPolicyTable().rowKeySet();
159
160         SetView<RendererEndpointKey> removedRendEps = Sets.difference(rendEpsBefore, rendEpsAfter);
161         removedRendEps.forEach(rEpKey -> fwManager.removeForwardingForEndpoint(rEpKey, policyCtxBefore));
162
163         fwManager.removeVxlanBridgeDomainsOnNodes(removedVppNodesByL2Fd);
164         fwManager.createVxlanBridgeDomainsOnNodes(createdVppNodesByL2Fd);
165
166         SetView<RendererEndpointKey> createdRendEps = Sets.difference(rendEpsAfter, rendEpsBefore);
167         createdRendEps.forEach(rEpKey -> fwManager.createForwardingForEndpoint(rEpKey, policyCtxAfter));
168
169         SetView<RendererEndpointKey> updatedRendEps = Sets.intersection(rendEpsBefore, rendEpsAfter);
170         // TODO think about all cases, but keep it simple for now
171         updatedRendEps.forEach(rEpKey -> fwManager.removeForwardingForEndpoint(rEpKey, policyCtxBefore));
172         updatedRendEps.forEach(rEpKey -> fwManager.createForwardingForEndpoint(rEpKey, policyCtxAfter));
173     }
174
175     private static MapDifference<String, Collection<NodeId>> createDiffForVppNodesByL2Fd(PolicyContext policyCtxBefore,
176             PolicyContext policyCtxAfter) {
177         ImmutableSet<RendererEndpointKey> rendEpsBefore = policyCtxBefore.getPolicyTable().rowKeySet();
178         ImmutableSet<RendererEndpointKey> rendEpsAfter = policyCtxAfter.getPolicyTable().rowKeySet();
179         SetMultimap<String, NodeId> vppNodesByL2FdBefore = resolveVppNodesByL2Fd(rendEpsBefore, policyCtxBefore);
180         SetMultimap<String, NodeId> vppNodesByL2FdAfter = resolveVppNodesByL2Fd(rendEpsAfter, policyCtxBefore);
181         return Maps.difference(vppNodesByL2FdBefore.asMap(), vppNodesByL2FdAfter.asMap());
182     }
183
184     private void rendererPolicyCreated(RendererPolicy rPolicy) {
185         PolicyContext policyCtx = new PolicyContext(rPolicy);
186         ImmutableSet<RendererEndpointKey> rEpKeys = policyCtx.getPolicyTable().rowKeySet();
187
188         SetMultimap<String, NodeId> vppNodesByL2Fd = resolveVppNodesByL2Fd(rEpKeys, policyCtx);
189         fwManager.createVxlanBridgeDomainsOnNodes(vppNodesByL2Fd);
190
191         rEpKeys.forEach(rEpKey -> fwManager.createForwardingForEndpoint(rEpKey, policyCtx));
192     }
193
194     private void rendererPolicyDeleted(RendererPolicy rendererPolicy) {
195         PolicyContext policyCtx = new PolicyContext(rendererPolicy);
196         ImmutableSet<RendererEndpointKey> rEpKeys = policyCtx.getPolicyTable().rowKeySet();
197
198         rEpKeys.forEach(rEpKey -> fwManager.removeForwardingForEndpoint(rEpKey, policyCtx));
199
200         SetMultimap<String, NodeId> vppNodesByL2Fd = resolveVppNodesByL2Fd(rEpKeys, policyCtx);
201         fwManager.removeVxlanBridgeDomainsOnNodes(vppNodesByL2Fd);
202     }
203
204     private static SetMultimap<String, NodeId> resolveVppNodesByL2Fd(Set<RendererEndpointKey> rEpKeys,
205             PolicyContext policyCtx) {
206         SetMultimap<String, NodeId> vppNodesByL2Fd = HashMultimap.create();
207         rEpKeys.stream()
208             .map(rEpKey -> KeyFactory.addressEndpointKey(rEpKey))
209             .map(addrEpKey -> policyCtx.getAddrEpByKey().get(addrEpKey))
210             .collect(Collectors.toSet())
211             .forEach(addrEpWithLoc -> {
212                 Optional<String> optL2Fd =
213                         ForwardingManager.resolveL2FloodDomain(addrEpWithLoc.getNetworkContainment());
214                 if (optL2Fd.isPresent()) {
215                     ExternalLocationCase rEpLoc = ForwardingManager.resolveAndValidateLocation(addrEpWithLoc);
216                     InstanceIdentifier<?> externalNodeMountPoint = rEpLoc.getExternalNodeMountPoint();
217                     NodeId vppNode = externalNodeMountPoint.firstKeyOf(Node.class).getNodeId();
218                     vppNodesByL2Fd.put(optL2Fd.get(), vppNode);
219                 }
220             });
221         return vppNodesByL2Fd;
222     }
223
224     @Subscribe
225     public void vppNodeChanged(NodeOperEvent event) {
226         switch (event.getDtoModificationType()) {
227             case CREATED:
228                 if (event.isAfterConnected()) {
229                     // TODO
230                 }
231                 break;
232             case UPDATED:
233                 if (!event.isBeforeConnected() && event.isAfterConnected()) {
234                     // TODO
235                 }
236                 break;
237             case DELETED:
238                 if (event.isBeforeConnected()) {
239                     // TODO
240                 }
241                 break;
242         }
243     }
244 }