VPP renderer: fixed imports after changes in vpp yang models
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / policy / BridgeDomainManagerImpl.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 import javax.annotation.Nullable;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.TimeoutException;
17 import com.google.common.base.Optional;
18 import com.google.common.base.Preconditions;
19 import com.google.common.util.concurrent.AsyncFunction;
20 import com.google.common.util.concurrent.CheckedFuture;
21 import com.google.common.util.concurrent.FutureCallback;
22 import com.google.common.util.concurrent.Futures;
23 import com.google.common.util.concurrent.ListenableFuture;
24 import com.google.common.util.concurrent.SettableFuture;
25 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
26 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
27 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
28 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
29 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
30 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
31 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
32 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
33 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
34 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
35 import org.opendaylight.groupbasedpolicy.renderer.vpp.api.BridgeDomainManager;
36 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.GbpBridgeDomain;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.GbpBridgeDomainKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.gbp.bridge.domain.PhysicalLocationRef;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VxlanVni;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.bridge.domains.BridgeDomain;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.bridge.domains.BridgeDomainKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.status.rev161005.BridgeDomainStatusAugmentation;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.status.rev161005.BridgeDomainStatusFields.BridgeDomainStatus;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.NodeVbridgeAugment;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyTypesVbridgeAugment;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyTypesVbridgeAugmentBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugment;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugmentBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.node.BridgeMember;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.topology.types.VbridgeTopologyBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.NodeVbridgeVlanAugment;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.NodeVbridgeVlanAugmentBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.TunnelTypeVlan;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.network.topology.topology.tunnel.parameters.VlanNetworkParametersBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vxlan.rev160429.TunnelTypeVxlan;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vxlan.rev160429.network.topology.topology.tunnel.parameters.VxlanTunnelParametersBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214._802dot1q;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
65 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
66 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
67 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
68 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
69 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypes;
70 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypesBuilder;
71 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.node.attributes.SupportingNodeBuilder;
72 import org.opendaylight.yangtools.concepts.ListenerRegistration;
73 import org.opendaylight.yangtools.yang.binding.DataObject;
74 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
77
78 public class BridgeDomainManagerImpl implements BridgeDomainManager {
79
80     private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainManagerImpl.class);
81     private static final TopologyId SUPPORTING_TOPOLOGY_NETCONF = new TopologyId("topology-netconf");
82     private static final TopologyTypes VBRIDGE_TOPOLOGY_TYPE = new TopologyTypesBuilder().addAugmentation(
83             TopologyTypesVbridgeAugment.class,
84             new TopologyTypesVbridgeAugmentBuilder().setVbridgeTopology(new VbridgeTopologyBuilder().build()).build())
85             .build();
86     private final DataBroker dataProvider;
87
88     private static final class ListenableFutureSetter<T extends DataObject>
89             implements ClusteredDataTreeChangeListener<T> {
90
91         private static final Logger LOG = LoggerFactory.getLogger(ListenableFutureSetter.class);
92         private final SettableFuture<Void> future;
93         private final ModificationType modificationForFutureSet;
94         private final DataTreeIdentifier<T> iid;
95         private final ListenerRegistration<ListenableFutureSetter<T>> registeredListener;
96
97         private ListenableFutureSetter(DataBroker dataProvider, SettableFuture<Void> future,
98                                        DataTreeIdentifier<T> iid, ModificationType modificationForFutureSet) {
99             this.future = Preconditions.checkNotNull(future);
100             Preconditions.checkArgument(!future.isDone());
101             this.modificationForFutureSet = Preconditions.checkNotNull(modificationForFutureSet);
102             this.iid = Preconditions.checkNotNull(iid);
103             registeredListener = dataProvider.registerDataTreeChangeListener(iid, this);
104             LOG.debug("Registered listener for path {}", iid.getRootIdentifier());
105         }
106
107         @Override
108         public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<T>> changes) {
109             changes.forEach(modification -> {
110                 final DataObjectModification<T> rootNode = modification.getRootNode();
111                 final ModificationType modificationType = rootNode.getModificationType();
112                 if (modificationType == modificationForFutureSet) {
113                     LOG.debug("{} in OPER DS: {}", modificationType.name(), iid.getRootIdentifier());
114                     final T data = rootNode.getDataAfter();
115                     // If waiting for bridge domain creation, do more specific check about BD status
116                     if (data != null && data instanceof BridgeDomain) {
117                         final BridgeDomain domain = (BridgeDomain) data;
118                         final BridgeDomainStatusAugmentation statusAugment =
119                                 domain.getAugmentation(BridgeDomainStatusAugmentation.class);
120                         final BridgeDomainStatus status = statusAugment.getBridgeDomainStatus();
121                         switch (status) {
122                             case Started: {
123                                 LOG.debug("Bridge domain {} started", domain.getName());
124                                 unregister(future.set(null));
125                                 break;
126                             }
127                             case Failed: {
128                                 LOG.warn("Bridge domain {} failed to start", domain.getName());
129                                 unregister(future.set(null));
130                                 break;
131                             }
132                             case Starting:
133                             case Stopped: {
134                                 LOG.debug("Bridge domain {} status changed to {}", domain.getName(), status.getName());
135                                 break;
136                             }
137                         }
138                     } else {
139                         unregister(future.set(null));
140                     }
141                 }
142             });
143         }
144
145         private void unregister(boolean _true) {
146             if (_true) {
147                 LOG.debug("Unregistering listener for path {}", iid.getRootIdentifier());
148                 if (registeredListener != null) {
149                     registeredListener.close();
150                 }
151             }
152         }
153     }
154
155     public BridgeDomainManagerImpl(DataBroker dataProvider) {
156         this.dataProvider = Preconditions.checkNotNull(dataProvider);
157     }
158
159     private static NodeBuilder createBasicVppNodeBuilder(NodeId nodeId) {
160         return new NodeBuilder().setNodeId(nodeId).setSupportingNode(Collections.singletonList(
161                 new SupportingNodeBuilder().setTopologyRef(SUPPORTING_TOPOLOGY_NETCONF).setNodeRef(nodeId).build()));
162     }
163
164     @Override
165     public ListenableFuture<Void> createVxlanBridgeDomainOnVppNode(@Nonnull final String bridgeDomainName,
166                                                                    @Nonnull final VxlanVni vni,
167                                                                    @Nonnull final NodeId vppNodeId) {
168         TopologyVbridgeAugment topologyAug = new TopologyVbridgeAugmentBuilder().setTunnelType(TunnelTypeVxlan.class)
169                 .setArpTermination(false)
170                 .setFlood(true)
171                 .setForward(true)
172                 .setLearn(true)
173                 .setUnknownUnicastFlood(true)
174                 .setTunnelParameters(new VxlanTunnelParametersBuilder().setVni(vni).build())
175                 .build();
176         return createBridgeDomainOnVppNode(bridgeDomainName, topologyAug,
177                 createBasicVppNodeBuilder(vppNodeId).build());
178     }
179
180     @Override
181     public ListenableFuture<Void> createVlanBridgeDomainOnVppNode(@Nonnull final String bridgeDomainName,
182                                                                   @Nonnull final VlanId vlanId,
183                                                                   @Nonnull final NodeId vppNodeId) {
184         TopologyVbridgeAugment topologyAug = new TopologyVbridgeAugmentBuilder().setTunnelType(TunnelTypeVlan.class)
185                 .setArpTermination(false)
186                 .setFlood(true)
187                 .setForward(true)
188                 .setLearn(true)
189                 .setUnknownUnicastFlood(true)
190                 .setTunnelParameters(
191                         new VlanNetworkParametersBuilder().setVlanId(vlanId).setVlanType(_802dot1q.class).build())
192                 .build();
193         InstanceIdentifier<GbpBridgeDomain> bridgeDomainConfigIid = InstanceIdentifier.builder(Config.class)
194                 .child(GbpBridgeDomain.class, new GbpBridgeDomainKey(bridgeDomainName))
195                 .build();
196         ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
197         CheckedFuture<Optional<GbpBridgeDomain>, ReadFailedException> futureTopology =
198                 rTx.read(LogicalDatastoreType.CONFIGURATION, bridgeDomainConfigIid);
199         rTx.close();
200         return Futures.transform(futureTopology, new AsyncFunction<Optional<GbpBridgeDomain>, Void>() {
201
202             @Override
203             public ListenableFuture<Void> apply(@Nonnull Optional<GbpBridgeDomain> optBridgeDomainConf) throws Exception {
204                 if (optBridgeDomainConf.isPresent() && optBridgeDomainConf.get().getPhysicalLocationRef() != null) {
205                     for (PhysicalLocationRef ref : optBridgeDomainConf.get().getPhysicalLocationRef()) {
206                         if (!ref.getNodeId().equals(vppNodeId)) continue; //not our referenced node skipping
207
208                         if (ref.getInterface() != null && ref.getInterface().size() > 0) {
209                             NodeVbridgeVlanAugment vppNodeVlanAug = new NodeVbridgeVlanAugmentBuilder()
210                                     .setSuperInterface(ref.getInterface().get(0)).build();
211                             Node vppNode = createBasicVppNodeBuilder(vppNodeId)
212                                     .addAugmentation(NodeVbridgeVlanAugment.class, vppNodeVlanAug).build();
213                             return createBridgeDomainOnVppNode(bridgeDomainName, topologyAug, vppNode);
214                         }
215                     }
216                 }
217                 return Futures.immediateFailedFuture(
218                         new Throwable("Failed to apply config for VLAN bridge domain " + bridgeDomainName));
219             }
220         });
221     }
222
223     /**
224      * Method checks whether bridge domain already exists in topology under its {@link TopologyId}. If not, BD is
225      * written into CONF DS (request for VBD) and registers listener which awaits result from VBD. Result can be
226      * checked in OPER DS as a {@link BridgeDomainStatus}. If status is {@link BridgeDomainStatus#Started}, listener
227      * unregisters itself and bridge domain creation in VBD is considered successful.
228      * <p>
229      * Next part creates request for {@link BridgeMember} in topology CONF DS and registers listener listening on
230      * topology OPER DS. If bridge member is created in VBD, listener is closed.
231      * <p>
232      * This process has limited time, limit is defined in {@link ForwardingManager#WAIT_FOR_BD_CREATION} to prevent
233      * stuck if VBD processing fails in some point.
234      *
235      * @param bridgeDomainName serving as a topology-id
236      * @param vBridgeAug       augmented data in BD
237      * @param vppNode          transformed into bridge member
238      * @return composed future which serves as a marker for caller method that the computation is done. If future is
239      * not returned in time, {@link TimeoutException} will be thrown there.
240      */
241     private ListenableFuture<Void> createBridgeDomainOnVppNode(@Nonnull final String bridgeDomainName,
242                                                                @Nonnull final TopologyVbridgeAugment vBridgeAug,
243                                                                @Nonnull final Node vppNode) {
244         final TopologyKey topologyKey = new TopologyKey(new TopologyId(bridgeDomainName));
245         final ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
246         final InstanceIdentifier<Topology> topologyIid = VppIidFactory.getTopologyIid(topologyKey);
247         final CheckedFuture<Optional<Topology>, ReadFailedException> optTopology =
248                 rTx.read(LogicalDatastoreType.CONFIGURATION, topologyIid);
249         rTx.close();
250         return Futures.transform(optTopology, new AsyncFunction<Optional<Topology>, Void>() {
251             @Override
252             public ListenableFuture<Void> apply(@Nonnull final Optional<Topology> optTopology)
253                     throws InterruptedException, ExecutionException {
254                 // Topology
255                 final SettableFuture<Void> topologyFuture = SettableFuture.create();
256                 if (!optTopology.isPresent()) {
257                     final WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
258                     final Topology topology = new TopologyBuilder().setKey(topologyKey)
259                             .setTopologyTypes(VBRIDGE_TOPOLOGY_TYPE)
260                             .addAugmentation(TopologyVbridgeAugment.class, vBridgeAug)
261                             .build();
262                     wTx.put(LogicalDatastoreType.CONFIGURATION, topologyIid, topology, true);
263                     Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
264
265                         @Override
266                         public void onSuccess(@Nullable final Void result) {
267                             final InstanceIdentifier<BridgeDomain> bridgeDomainStateIid =
268                                     VppIidFactory.getBridgeDomainStateIid(new BridgeDomainKey(bridgeDomainName));
269                             final DataTreeIdentifier<BridgeDomain> bridgeDomainStateIidDTI = new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
270                                     bridgeDomainStateIid);
271                             new ListenableFutureSetter<>(dataProvider, topologyFuture, bridgeDomainStateIidDTI, ModificationType.WRITE);
272                         }
273
274                         @Override
275                         public void onFailure(@Nonnull Throwable t) {
276                             LOG.warn("Request create topology for VBD was not stored to CONF DS. {}", topologyIid, t);
277                             topologyFuture.setException(new Exception("Cannot send request to VBD."));
278                         }
279                     });
280                 } else {
281                     topologyFuture.set(null);
282                 }
283                 return Futures.transform(topologyFuture, new AsyncFunction<Void, Void>() {
284                     @Override
285                     public ListenableFuture<Void> apply(@Nonnull Void topologyInput) throws Exception {
286                         // Bridge member
287                         final SettableFuture<Void> futureBridgeMember = SettableFuture.create();
288                         final InstanceIdentifier<Node> nodeIid = VppIidFactory.getNodeIid(topologyKey, vppNode.getKey());
289                         final WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
290                         wTx.put(LogicalDatastoreType.CONFIGURATION, nodeIid, vppNode);
291                         Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
292
293                             @Override
294                             public void onSuccess(@Nullable final Void _void) {
295                                 final DataTreeIdentifier<BridgeMember> bridgeMemberIid =
296                                         new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
297                                                 nodeIid.augmentation(NodeVbridgeAugment.class).child(BridgeMember.class));
298                                 LOG.debug("Request create node in topology for VBD was stored to CONF DS. {}", nodeIid);
299                                 new ListenableFutureSetter<>(dataProvider, futureBridgeMember, bridgeMemberIid,
300                                         ModificationType.WRITE);
301                             }
302
303                             @Override
304                             public void onFailure(@Nonnull final Throwable t) {
305                                 LOG.warn("Request create node in topology for VBD was not stored to CONF DS. {}", nodeIid, t);
306                                 futureBridgeMember.setException(new Exception("Cannot send request to VBD."));
307                             }
308                         });
309                         return futureBridgeMember;
310                     }
311                 });
312             }
313         });
314     }
315
316     @Override
317     public ListenableFuture<Void> removeBridgeDomainFromVppNode(@Nonnull final String bridgeDomainName,
318                                                                 @Nonnull final NodeId vppNode) {
319         WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
320         InstanceIdentifier<Node> nodeIid =
321                 VppIidFactory.getNodeIid(new TopologyKey(new TopologyId(bridgeDomainName)), new NodeKey(vppNode));
322         wTx.delete(LogicalDatastoreType.CONFIGURATION, nodeIid);
323         SettableFuture<Void> future = SettableFuture.create();
324         Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
325
326             @Override
327             public void onSuccess(Void result) {
328                 DataTreeIdentifier<BridgeMember> bridgeMemberIid =
329                         new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
330                                 nodeIid.augmentation(NodeVbridgeAugment.class).child(BridgeMember.class));
331                 LOG.debug("Request delete node in topology for VBD was stored to CONF DS. {}", nodeIid);
332                 new ListenableFutureSetter<>(dataProvider, future, bridgeMemberIid, ModificationType.DELETE);
333             }
334
335             @Override
336             public void onFailure(@Nonnull Throwable t) {
337                 LOG.warn("Request delete node in topology for VBD was not stored to CONF DS. {}", nodeIid, t);
338                 future.setException(new Exception("Cannot send request to VBD."));
339             }
340         });
341         return future;
342     }
343 }