Implementing VNI generation for VBD
[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 java.util.Arrays;
12 import java.util.Collection;
13 import java.util.concurrent.TimeUnit;
14
15 import javax.annotation.Nonnull;
16
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
19 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
20 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
21 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
22 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
23 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
24 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
27 import org.opendaylight.groupbasedpolicy.renderer.vpp.api.BridgeDomainManager;
28 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.BridgeDomain;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.BridgeDomainKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.bridge.domain.PhysicalLocationRef;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.NodeVbridgeAugment;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyTypesVbridgeAugment;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyTypesVbridgeAugmentBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugment;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugmentBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.node.BridgeMember;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.topology.types.VbridgeTopologyBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.NodeVbridgeVlanAugment;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.NodeVbridgeVlanAugmentBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.TunnelTypeVlan;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.network.topology.topology.tunnel.parameters.VlanNetworkParametersBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vxlan.rev160429.TunnelTypeVxlan;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vxlan.rev160429.network.topology.topology.tunnel.parameters.VxlanTunnelParametersBuilder;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypes;
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypesBuilder;
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.node.attributes.SupportingNodeBuilder;
59 import org.opendaylight.yangtools.concepts.ListenerRegistration;
60 import org.opendaylight.yangtools.yang.binding.DataObject;
61 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65 import com.google.common.annotations.VisibleForTesting;
66 import com.google.common.base.Optional;
67 import com.google.common.base.Preconditions;
68 import com.google.common.util.concurrent.AsyncFunction;
69 import com.google.common.util.concurrent.CheckedFuture;
70 import com.google.common.util.concurrent.FutureCallback;
71 import com.google.common.util.concurrent.Futures;
72 import com.google.common.util.concurrent.ListenableFuture;
73 import com.google.common.util.concurrent.SettableFuture;
74
75 public class BridgeDomainManagerImpl implements BridgeDomainManager {
76
77     private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainManagerImpl.class);
78     private static final TopologyId SUPPORTING_TOPOLOGY_NETCONF = new TopologyId("topology-netconf");
79     private static final TopologyTypes VBRIDGE_TOPOLOGY_TYPE = new TopologyTypesBuilder().addAugmentation(
80             TopologyTypesVbridgeAugment.class,
81             new TopologyTypesVbridgeAugmentBuilder().setVbridgeTopology(new VbridgeTopologyBuilder().build()).build())
82         .build();
83     @VisibleForTesting
84     static long WAIT_FOR_TOPOLOGY_CREATION = 10; // seconds
85     private final DataBroker dataProvder;
86
87     private static final class ListenableFutureSetter<T extends DataObject>
88             implements DataTreeChangeListener<T> {
89
90         private static final Logger LOG = LoggerFactory.getLogger(ListenableFutureSetter.class);
91         private final SettableFuture<Void> future;
92         private final ModificationType modificationForFutureSet;
93         private final DataTreeIdentifier<T> iid;
94         private final ListenerRegistration<ListenableFutureSetter<T>> registeredListener;
95
96         private ListenableFutureSetter(DataBroker dataProvider, SettableFuture<Void> future,
97                 DataTreeIdentifier<T> iid, ModificationType modificationForFutureSet) {
98             this.future = Preconditions.checkNotNull(future);
99             Preconditions.checkArgument(!future.isDone());
100             this.modificationForFutureSet = Preconditions.checkNotNull(modificationForFutureSet);
101             this.iid = Preconditions.checkNotNull(iid);
102             registeredListener = dataProvider.registerDataTreeChangeListener(iid, this);
103             LOG.trace("Registered listener for path {}", iid.getRootIdentifier());
104         }
105
106         @Override
107         public void onDataTreeChanged(Collection<DataTreeModification<T>> changes) {
108             changes.forEach(modif -> {
109                 DataObjectModification<T> rootNode = modif.getRootNode();
110                 ModificationType modificationType = rootNode.getModificationType();
111                 if (modificationType == modificationForFutureSet) {
112                     LOG.debug("{} in OPER DS: {}", modificationType.name(), iid.getRootIdentifier());
113                     unregisterOnTrue(future.set(null));
114                 }
115             });
116         }
117
118         private void unregisterOnTrue(boolean _true) {
119             if (_true) {
120                 LOG.trace("Unregistering listener for path {}", iid.getRootIdentifier());
121                 if (registeredListener != null) {
122                     registeredListener.close();
123                 }
124             }
125         }
126     }
127
128     public BridgeDomainManagerImpl(DataBroker dataProvder) {
129         this.dataProvder = Preconditions.checkNotNull(dataProvder);
130     }
131
132     @Override
133     public ListenableFuture<Void> createVxlanBridgeDomainOnVppNode(@Nonnull String bridgeDomainName,
134             @Nonnull VxlanVni vni, @Nonnull NodeId vppNodeId) {
135         TopologyVbridgeAugment topoAug = new TopologyVbridgeAugmentBuilder().setTunnelType(TunnelTypeVxlan.class)
136             .setArpTermination(false)
137             .setFlood(true)
138             .setForward(true)
139             .setLearn(true)
140             .setUnknownUnicastFlood(true)
141             .setTunnelParameters(new VxlanTunnelParametersBuilder().setVni(vni).build())
142             .build();
143         return createBridgeDomainOnVppNode(bridgeDomainName, topoAug, createBasicVppNodeBuilder(vppNodeId).build());
144     }
145
146     @Override
147     public ListenableFuture<Void> createVlanBridgeDomainOnVppNode(@Nonnull String bridgeDomainName,
148             @Nonnull VlanId vlanId, @Nonnull NodeId vppNodeId) {
149         TopologyVbridgeAugment topoAug = new TopologyVbridgeAugmentBuilder().setTunnelType(TunnelTypeVlan.class)
150             .setArpTermination(false)
151             .setFlood(true)
152             .setForward(true)
153             .setLearn(true)
154             .setUnknownUnicastFlood(true)
155             .setTunnelParameters(new VlanNetworkParametersBuilder().setVlanId(vlanId).build())
156             .build();
157         InstanceIdentifier<BridgeDomain> bridgeDomainConfigIid = InstanceIdentifier.builder(Config.class)
158             .child(BridgeDomain.class, new BridgeDomainKey(bridgeDomainName))
159             .build();
160         ReadOnlyTransaction rTx = dataProvder.newReadOnlyTransaction();
161         CheckedFuture<Optional<BridgeDomain>, ReadFailedException> futureTopology =
162                 rTx.read(LogicalDatastoreType.CONFIGURATION, bridgeDomainConfigIid);
163         rTx.close();
164         return Futures.transform(futureTopology, new AsyncFunction<Optional<BridgeDomain>, Void>() {
165
166             @Override
167             public ListenableFuture<Void> apply(Optional<BridgeDomain> optBridgeDomainConf) throws Exception {
168                 if (optBridgeDomainConf.isPresent() && optBridgeDomainConf.get().getPhysicalLocationRef() != null) {
169                     for (PhysicalLocationRef ref : optBridgeDomainConf.get().getPhysicalLocationRef()) {
170                         if (ref.getInterface() != null && ref.getInterface().size() > 0) {
171                             NodeVbridgeVlanAugment vppNodeVlanAug = new NodeVbridgeVlanAugmentBuilder()
172                                 .setSuperInterface(ref.getInterface().get(0)).build();
173                             Node vppNode = createBasicVppNodeBuilder(vppNodeId)
174                                 .addAugmentation(vppNodeVlanAug.getClass(), vppNodeVlanAug).build();
175                             return createBridgeDomainOnVppNode(bridgeDomainName, topoAug, vppNode);
176                         }
177                     }
178                 }
179                 return Futures.immediateFailedFuture(
180                         new Throwable("Failed to apply config for VLAN bridge domain " + bridgeDomainName));
181             }
182         });
183     }
184
185     private static NodeBuilder createBasicVppNodeBuilder(NodeId nodeId) {
186         return new NodeBuilder().setNodeId(nodeId).setSupportingNode(Arrays.asList(
187                 new SupportingNodeBuilder().setTopologyRef(SUPPORTING_TOPOLOGY_NETCONF).setNodeRef(nodeId).build()));
188     }
189
190     private ListenableFuture<Void> createBridgeDomainOnVppNode(@Nonnull String bridgeDomainName,
191             final TopologyVbridgeAugment vBridgeAug, Node vppNode) {
192         TopologyKey topologyKey = new TopologyKey(new TopologyId(bridgeDomainName));
193         ReadOnlyTransaction rTx = dataProvder.newReadOnlyTransaction();
194         InstanceIdentifier<Topology> topologyIid = VppIidFactory.getTopologyIid(topologyKey);
195         CheckedFuture<Optional<Topology>, ReadFailedException> futureTopology =
196                 rTx.read(LogicalDatastoreType.CONFIGURATION, topologyIid);
197         rTx.close();
198         return Futures.transform(futureTopology, new AsyncFunction<Optional<Topology>, Void>() {
199
200             @Override
201             public ListenableFuture<Void> apply(Optional<Topology> optTopology) throws Exception {
202                 SettableFuture<Void> topoFuture = SettableFuture.create();
203                 if (!optTopology.isPresent()) {
204                     WriteTransaction wTx = dataProvder.newWriteOnlyTransaction();
205                     Topology topology = new TopologyBuilder().setKey(topologyKey)
206                         .setTopologyTypes(VBRIDGE_TOPOLOGY_TYPE)
207                         .addAugmentation(TopologyVbridgeAugment.class, vBridgeAug)
208                         .build();
209                     wTx.put(LogicalDatastoreType.CONFIGURATION, topologyIid,
210                             topology, true);
211                     Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
212
213                         @Override
214                         public void onSuccess(Void result) {
215                             DataTreeIdentifier<Topology> topoIdentifier =
216                                     new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, topologyIid);
217                             new ListenableFutureSetter<>(dataProvder, topoFuture, topoIdentifier,
218                                     ModificationType.WRITE);
219                         }
220
221                         @Override
222                         public void onFailure(Throwable t) {
223                             LOG.warn("Request create topology for VBD was not stored to CONF DS. {}", topologyIid, t);
224                             topoFuture.setException(new Exception("Cannot send request to VBD."));
225                         }});
226                 } else {
227                     topoFuture.set(null);
228                 }
229                 topoFuture.get(WAIT_FOR_TOPOLOGY_CREATION, TimeUnit.SECONDS);
230                 WriteTransaction wTx = dataProvder.newWriteOnlyTransaction();
231                 InstanceIdentifier<Node> nodeIid = VppIidFactory.getNodeIid(topologyKey, vppNode.getKey());
232                 wTx.put(LogicalDatastoreType.CONFIGURATION, nodeIid, vppNode);
233                 SettableFuture<Void> future = SettableFuture.create();
234                 Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
235
236                     @Override
237                     public void onSuccess(Void result) {
238                         DataTreeIdentifier<BridgeMember> bridgeMemberIid =
239                                 new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
240                                         nodeIid.augmentation(NodeVbridgeAugment.class).child(BridgeMember.class));
241                         LOG.debug("Request create node in topology for VBD was stored to CONF DS. {}", nodeIid);
242                         new ListenableFutureSetter<>(dataProvder, future, bridgeMemberIid,
243                                 ModificationType.WRITE);
244                     }
245
246                     @Override
247                     public void onFailure(Throwable t) {
248                         LOG.warn("Request create node in topology for VBD was not stored to CONF DS. {}", nodeIid, t);
249                         future.setException(new Exception("Cannot send request to VBD."));
250                     }
251                 });
252                 return future;
253             }
254         });
255     }
256
257     @Override
258     public ListenableFuture<Void> removeBridgeDomainFromVppNode(@Nonnull String bridgeDomainName, NodeId vppNode) {
259         WriteTransaction wTx = dataProvder.newWriteOnlyTransaction();
260         InstanceIdentifier<Node> nodeIid =
261                 VppIidFactory.getNodeIid(new TopologyKey(new TopologyId(bridgeDomainName)), new NodeKey(vppNode));
262         wTx.delete(LogicalDatastoreType.CONFIGURATION, nodeIid);
263         SettableFuture<Void> future = SettableFuture.create();
264         Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
265
266             @Override
267             public void onSuccess(Void result) {
268                 DataTreeIdentifier<BridgeMember> bridgeMemberIid =
269                         new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
270                                 nodeIid.augmentation(NodeVbridgeAugment.class).child(BridgeMember.class));
271                 LOG.debug("Request delete node in topology for VBD was stored to CONF DS. {}", nodeIid);
272                 new ListenableFutureSetter<>(dataProvder, future, bridgeMemberIid, ModificationType.DELETE);
273             }
274
275             @Override
276             public void onFailure(Throwable t) {
277                 LOG.warn("Request delete node in topology for VBD was not stored to CONF DS. {}", nodeIid, t);
278                 future.setException(new Exception("Cannot send request to VBD."));
279             }
280         });
281         return future;
282     }
283
284 }