Implementing VBD API in Vpp renderer
[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 javax.annotation.Nonnull;
12
13 import org.opendaylight.controller.config.yang.config.vpp_provider.impl.VppRenderer;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.groupbasedpolicy.renderer.vpp.event.NodeOperEvent;
18 import org.opendaylight.groupbasedpolicy.renderer.vpp.event.RendererPolicyConfEvent;
19 import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;
20 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.KeyFactory;
21 import org.opendaylight.groupbasedpolicy.util.IidFactory;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.NetworkContainment;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.Containment;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.containment.ForwardingContextContainment;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.containment.NetworkDomainContainment;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.LocationType;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.L2FloodDomain;
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.endpoints.AddressEndpointWithLocation;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpointKey;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 import com.google.common.base.Preconditions;
37 import com.google.common.base.Strings;
38 import com.google.common.collect.ImmutableSet;
39 import com.google.common.collect.Sets;
40 import com.google.common.collect.Sets.SetView;
41 import com.google.common.eventbus.Subscribe;
42 import com.google.common.util.concurrent.FutureCallback;
43 import com.google.common.util.concurrent.Futures;
44 import com.google.common.util.concurrent.ListenableFuture;
45
46 public class VppRendererPolicyManager {
47
48     private static final Logger LOG = LoggerFactory.getLogger(VppRendererPolicyManager.class);
49     private final InterfaceManager ifaceManager;
50     private final DataBroker dataProvider;
51
52     public VppRendererPolicyManager(@Nonnull InterfaceManager ifaceManager, @Nonnull DataBroker dataProvider) {
53         this.ifaceManager = Preconditions.checkNotNull(ifaceManager);
54         this.dataProvider = Preconditions.checkNotNull(dataProvider);
55     }
56
57     @Subscribe
58     public void rendererPolicyChanged(RendererPolicyConfEvent event) {
59         RendererPolicyBuilder responseBulder = new RendererPolicyBuilder();
60         switch (event.getDtoModificationType()) {
61             case CREATED:
62                 responseBulder.setVersion(event.getAfter().get().getVersion());
63                 rendererPolicyCreated(event.getAfter().get());
64                 break;
65             case UPDATED:
66                 RendererPolicy rPolicyBefore = event.getBefore().get();
67                 RendererPolicy rPolicyAfter = event.getAfter().get();
68                 responseBulder.setVersion(rPolicyAfter.getVersion());
69                 if (!isConfigurationChanged(rPolicyBefore, rPolicyAfter)) {
70                     LOG.debug("Configuration is not changed only updating config version from {} to {}",
71                             rPolicyBefore.getVersion(), rPolicyAfter.getVersion());
72                 } else {
73                     // TODO collect unconfigured rules and put them to responseBuilder
74                     rendererPolicyUpdated(rPolicyBefore, rPolicyAfter);
75                 }
76                 break;
77             case DELETED:
78                 responseBulder.setVersion(event.getBefore().get().getVersion());
79                 rendererPolicyDeleted(event.getBefore().get());
80                 break;
81         }
82         WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
83         RendererPolicy response = responseBulder.build();
84         wTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.rendererIid(VppRenderer.NAME).child(RendererPolicy.class),
85                 response, true);
86         Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
87
88             @Override
89             public void onSuccess(Void result) {
90                 LOG.debug("Renderer updated renderer policy {}", response);
91             }
92
93             @Override
94             public void onFailure(Throwable t) {
95                 LOG.warn("Renderer DIDN'T update renderer-policy {}", response);
96             }
97         });
98     }
99
100     private boolean isConfigurationChanged(RendererPolicy before, RendererPolicy after) {
101         if (before.getConfiguration() == null && after.getConfiguration() == null) {
102             return false;
103         }
104         return true;
105     }
106
107     private void rendererPolicyUpdated(RendererPolicy rPolicyBefore, RendererPolicy rPolicyAfter) {
108         PolicyContext policyCtxBefore = new PolicyContext(rPolicyBefore);
109         PolicyContext policyCtxAfter = new PolicyContext(rPolicyAfter);
110         ImmutableSet<RendererEndpointKey> rendEpsBefore = policyCtxBefore.getPolicyTable().rowKeySet();
111         ImmutableSet<RendererEndpointKey> rendEpsAfter = policyCtxAfter.getPolicyTable().rowKeySet();
112
113         SetView<RendererEndpointKey> removedRendEps = Sets.difference(rendEpsBefore, rendEpsAfter);
114         removedRendEps.forEach(rEpKey -> rendererEndpointDeleted(rEpKey, policyCtxBefore));
115
116         SetView<RendererEndpointKey> createdRendEps = Sets.difference(rendEpsAfter, rendEpsBefore);
117         createdRendEps.forEach(rEpKey -> rendererEndpointCreated(rEpKey, policyCtxAfter));
118
119         SetView<RendererEndpointKey> updatedRendEps = Sets.intersection(rendEpsBefore, rendEpsAfter);
120         // TODO think about all cases, but keep it simple for now
121         updatedRendEps.forEach(rEpKey -> rendererEndpointDeleted(rEpKey, policyCtxBefore));
122         updatedRendEps.forEach(rEpKey -> rendererEndpointCreated(rEpKey, policyCtxAfter));
123     }
124
125     private void rendererPolicyCreated(RendererPolicy rPolicy) {
126         PolicyContext policyCtx = new PolicyContext(rPolicy);
127
128         // TODO create topology for each L2FloodDomain in RendererForwarding
129
130         policyCtx.getPolicyTable().rowKeySet().forEach(rEpKey -> rendererEndpointCreated(rEpKey, policyCtx));
131     }
132
133     private void rendererEndpointCreated(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
134         AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
135         ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp);
136         if (Strings.isNullOrEmpty(rEpLoc.getExternalNodeConnector())) {
137             // TODO add it to the status for renderer manager
138             LOG.info("Rednerer endpoint does not have external-node-connector therefore it is ignored {}", rEp);
139             return;
140         }
141
142         // TODO add rEpLoc.getExternalNodeMountPoint() to VBD as node
143
144         if (Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
145             String l2FloodDomain = resolveL2FloodDomain(rEp.getNetworkContainment());
146             if (Strings.isNullOrEmpty(l2FloodDomain)) {
147                 // TODO add it to the status for renderer manager
148                 LOG.info("Rednerer endpoint does not have l2FloodDomain as network containment {}", rEp);
149                 return;
150             }
151             ListenableFuture<Void> futureAddBridgeDomainToInterface =
152                     ifaceManager.addBridgeDomainToInterface(l2FloodDomain, rEp);
153             Futures.addCallback(futureAddBridgeDomainToInterface, new FutureCallback<Void>() {
154
155                 @Override
156                 public void onSuccess(Void result) {
157                     LOG.debug("Interface added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp);
158                 }
159
160                 @Override
161                 public void onFailure(Throwable t) {
162                     // TODO add it to the status for renderer manager
163                     LOG.warn("Interface was not added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp, t);
164                 }
165             });
166         }
167     }
168
169     private void rendererPolicyDeleted(RendererPolicy rendererPolicy) {
170         PolicyContext policyCtx = new PolicyContext(rendererPolicy);
171
172         // TODO delete topology for each L2FloodDomain in RendererForwarding
173
174         policyCtx.getPolicyTable().rowKeySet().forEach(rEpKey -> rendererEndpointDeleted(rEpKey, policyCtx));
175     }
176
177     private void rendererEndpointDeleted(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
178         AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
179         ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp);
180         if (Strings.isNullOrEmpty(rEpLoc.getExternalNodeConnector())) {
181             // nothing was created for endpoint therefore nothing is removed
182             return;
183         }
184
185         // TODO remove rEpLoc.getExternalNodeMountPoint() to VBD as node
186
187         if (!Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
188             ListenableFuture<Void> futureAddBridgeDomainToInterface = ifaceManager.deleteBridgeDomainFromInterface(rEp);
189             Futures.addCallback(futureAddBridgeDomainToInterface, new FutureCallback<Void>() {
190
191                 @Override
192                 public void onSuccess(Void result) {
193                     LOG.debug("bridge-domain was deleted from interface for endpoint {}", rEp);
194                 }
195
196                 @Override
197                 public void onFailure(Throwable t) {
198                     // TODO add it to the status for renderer manager
199                     LOG.warn("bridge-domain was not deleted from interface for endpoint {}", rEp, t);
200                 }
201             });
202         }
203     }
204
205     private static String resolveL2FloodDomain(NetworkContainment netCont) {
206         if (netCont == null) {
207             return null;
208         }
209         Containment containment = netCont.getContainment();
210         if (containment instanceof ForwardingContextContainment) {
211             ForwardingContextContainment fwCtxCont = (ForwardingContextContainment) containment;
212             if (fwCtxCont.getContextType().isAssignableFrom(L2FloodDomain.class)) {
213                 return fwCtxCont.getContextId() == null ? null : fwCtxCont.getContextId().getValue();
214             }
215         }
216         if (containment instanceof NetworkDomainContainment) {
217             // TODO address missing impl
218             LOG.info("Network domain containment in endpoint is not supported yet. {}", netCont);
219             return null;
220         }
221         return null;
222     }
223
224     private static ExternalLocationCase resolveAndValidateLocation(AddressEndpointWithLocation addrEpWithLoc) {
225         LocationType locationType = addrEpWithLoc.getAbsoluteLocation().getLocationType();
226         if (!(locationType instanceof ExternalLocationCase)) {
227             throw new IllegalStateException("Endpoint does not have external location " + addrEpWithLoc);
228         }
229         ExternalLocationCase result = (ExternalLocationCase) locationType;
230         if (result.getExternalNodeMountPoint() == null) {
231             throw new IllegalStateException("Endpoint does not have external-node-mount-point " + addrEpWithLoc);
232         }
233         return result;
234     }
235
236     @Subscribe
237     public void vppNodeChanged(NodeOperEvent event) {
238         switch (event.getDtoModificationType()) {
239             case CREATED:
240                 if (event.isAfterConnected()) {
241                     // TODO
242                 }
243                 break;
244             case UPDATED:
245                 if (!event.isBeforeConnected() && event.isAfterConnected()) {
246                     // TODO
247                 }
248                 break;
249             case DELETED:
250                 if (event.isBeforeConnected()) {
251                     // TODO
252                 }
253                 break;
254         }
255     }
256 }