2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.policy;
11 import java.util.Arrays;
12 import java.util.Collection;
14 import javax.annotation.Nonnull;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
18 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
19 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
20 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
21 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
22 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
23 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.api.BridgeDomainManager;
27 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.BridgeDomain;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.BridgeDomainKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.bridge.domain.PhysicalLocationRef;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.NodeVbridgeAugment;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyTypesVbridgeAugment;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyTypesVbridgeAugmentBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugment;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugmentBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.node.BridgeMember;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.topology.types.VbridgeTopologyBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.NodeVbridgeVlanAugment;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.NodeVbridgeVlanAugmentBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.TunnelTypeVlan;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.network.topology.topology.tunnel.parameters.VlanNetworkParametersBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vxlan.rev160429.TunnelTypeVxlan;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vxlan.rev160429.network.topology.topology.tunnel.parameters.VxlanTunnelParametersBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1q;
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;
65 import com.google.common.base.Optional;
66 import com.google.common.base.Preconditions;
67 import com.google.common.util.concurrent.AsyncFunction;
68 import com.google.common.util.concurrent.CheckedFuture;
69 import com.google.common.util.concurrent.FutureCallback;
70 import com.google.common.util.concurrent.Futures;
71 import com.google.common.util.concurrent.ListenableFuture;
72 import com.google.common.util.concurrent.SettableFuture;
74 public class BridgeDomainManagerImpl implements BridgeDomainManager {
76 private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainManagerImpl.class);
77 private static final TopologyId SUPPORTING_TOPOLOGY_NETCONF = new TopologyId("topology-netconf");
78 private static final TopologyTypes VBRIDGE_TOPOLOGY_TYPE = new TopologyTypesBuilder().addAugmentation(
79 TopologyTypesVbridgeAugment.class,
80 new TopologyTypesVbridgeAugmentBuilder().setVbridgeTopology(new VbridgeTopologyBuilder().build()).build())
82 private final DataBroker dataProvder;
84 private static final class ListenableFutureSetter<T extends DataObject>
85 implements DataTreeChangeListener<T> {
87 private static final Logger LOG = LoggerFactory.getLogger(ListenableFutureSetter.class);
88 private final SettableFuture<Void> future;
89 private final ModificationType modificationForFutureSet;
90 private final DataTreeIdentifier<T> iid;
91 private final ListenerRegistration<ListenableFutureSetter<T>> registeredListener;
93 private ListenableFutureSetter(DataBroker dataProvider, SettableFuture<Void> future,
94 DataTreeIdentifier<T> iid, ModificationType modificationForFutureSet) {
95 this.future = Preconditions.checkNotNull(future);
96 Preconditions.checkArgument(!future.isDone());
97 this.modificationForFutureSet = Preconditions.checkNotNull(modificationForFutureSet);
98 this.iid = Preconditions.checkNotNull(iid);
99 registeredListener = dataProvider.registerDataTreeChangeListener(iid, this);
100 LOG.debug("Registered listener for path {}", iid.getRootIdentifier());
104 public void onDataTreeChanged(Collection<DataTreeModification<T>> changes) {
105 changes.forEach(modif -> {
106 DataObjectModification<T> rootNode = modif.getRootNode();
107 ModificationType modificationType = rootNode.getModificationType();
108 if (modificationType == modificationForFutureSet) {
109 LOG.debug("{} in OPER DS: {}", modificationType.name(), iid.getRootIdentifier());
110 unregisterOnTrue(future.set(null));
115 private void unregisterOnTrue(boolean _true) {
117 LOG.debug("Unregistering listener for path {}", iid.getRootIdentifier());
118 if (registeredListener != null) {
119 registeredListener.close();
125 public BridgeDomainManagerImpl(DataBroker dataProvder) {
126 this.dataProvder = Preconditions.checkNotNull(dataProvder);
130 public ListenableFuture<Void> createVxlanBridgeDomainOnVppNode(@Nonnull String bridgeDomainName,
131 @Nonnull VxlanVni vni, @Nonnull NodeId vppNodeId) {
132 TopologyVbridgeAugment topoAug = new TopologyVbridgeAugmentBuilder().setTunnelType(TunnelTypeVxlan.class)
133 .setArpTermination(false)
137 .setUnknownUnicastFlood(true)
138 .setTunnelParameters(new VxlanTunnelParametersBuilder().setVni(vni).build())
140 return createBridgeDomainOnVppNode(bridgeDomainName, topoAug,
141 createBasicVppNodeBuilder(vppNodeId).build());
145 public ListenableFuture<Void> createVlanBridgeDomainOnVppNode(@Nonnull String bridgeDomainName,
146 @Nonnull VlanId vlanId, @Nonnull NodeId vppNodeId) {
147 TopologyVbridgeAugment topoAug = new TopologyVbridgeAugmentBuilder().setTunnelType(TunnelTypeVlan.class)
148 .setArpTermination(false)
152 .setUnknownUnicastFlood(true)
153 .setTunnelParameters(
154 new VlanNetworkParametersBuilder().setVlanId(vlanId).setVlanType(_802dot1q.class).build())
156 InstanceIdentifier<BridgeDomain> bridgeDomainConfigIid = InstanceIdentifier.builder(Config.class)
157 .child(BridgeDomain.class, new BridgeDomainKey(bridgeDomainName))
159 ReadOnlyTransaction rTx = dataProvder.newReadOnlyTransaction();
160 CheckedFuture<Optional<BridgeDomain>, ReadFailedException> futureTopology =
161 rTx.read(LogicalDatastoreType.CONFIGURATION, bridgeDomainConfigIid);
163 return Futures.transform(futureTopology, new AsyncFunction<Optional<BridgeDomain>, Void>() {
166 public ListenableFuture<Void> apply(Optional<BridgeDomain> optBridgeDomainConf) throws Exception {
167 if (optBridgeDomainConf.isPresent() && optBridgeDomainConf.get().getPhysicalLocationRef() != null) {
168 for (PhysicalLocationRef ref : optBridgeDomainConf.get().getPhysicalLocationRef()) {
169 if (!ref.getNodeId().equals(vppNodeId)) continue; //not our referenced node skipping
171 if (ref.getInterface() != null && ref.getInterface().size() > 0) {
172 NodeVbridgeVlanAugment vppNodeVlanAug = new NodeVbridgeVlanAugmentBuilder()
173 .setSuperInterface(ref.getInterface().get(0)).build();
174 Node vppNode = createBasicVppNodeBuilder(vppNodeId)
175 .addAugmentation(NodeVbridgeVlanAugment.class, vppNodeVlanAug).build();
176 return createBridgeDomainOnVppNode(bridgeDomainName, topoAug, vppNode);
180 return Futures.immediateFailedFuture(
181 new Throwable("Failed to apply config for VLAN bridge domain " + bridgeDomainName));
186 private static NodeBuilder createBasicVppNodeBuilder(NodeId nodeId) {
187 return new NodeBuilder().setNodeId(nodeId).setSupportingNode(Arrays.asList(
188 new SupportingNodeBuilder().setTopologyRef(SUPPORTING_TOPOLOGY_NETCONF).setNodeRef(nodeId).build()));
191 private ListenableFuture<Void> createBridgeDomainOnVppNode(@Nonnull String bridgeDomainName,
192 final TopologyVbridgeAugment vBridgeAug, Node vppNode) {
193 TopologyKey topologyKey = new TopologyKey(new TopologyId(bridgeDomainName));
194 ReadOnlyTransaction rTx = dataProvder.newReadOnlyTransaction();
195 InstanceIdentifier<Topology> topologyIid = VppIidFactory.getTopologyIid(topologyKey);
196 CheckedFuture<Optional<Topology>, ReadFailedException> futureTopology =
197 rTx.read(LogicalDatastoreType.CONFIGURATION, topologyIid);
199 return Futures.transform(futureTopology, new AsyncFunction<Optional<Topology>, Void>() {
202 public ListenableFuture<Void> apply(Optional<Topology> optTopology) throws Exception {
203 WriteTransaction wTx = dataProvder.newWriteOnlyTransaction();
204 if (!optTopology.isPresent()) {
205 Topology topology = new TopologyBuilder().setKey(topologyKey)
206 .setTopologyTypes(VBRIDGE_TOPOLOGY_TYPE)
207 .addAugmentation(TopologyVbridgeAugment.class, vBridgeAug)
209 wTx.put(LogicalDatastoreType.CONFIGURATION, topologyIid,
212 InstanceIdentifier<Node> nodeIid = VppIidFactory.getNodeIid(topologyKey, vppNode.getKey());
213 wTx.put(LogicalDatastoreType.CONFIGURATION, nodeIid, vppNode);
214 SettableFuture<Void> future = SettableFuture.create();
215 Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
218 public void onSuccess(Void result) {
219 DataTreeIdentifier<BridgeMember> bridgeMemberIid =
220 new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
221 nodeIid.augmentation(NodeVbridgeAugment.class).child(BridgeMember.class));
222 LOG.debug("Request create node in topology for VBD was stored to CONF DS. {}", nodeIid);
223 new ListenableFutureSetter<>(dataProvder, future, bridgeMemberIid,
224 ModificationType.WRITE);
228 public void onFailure(Throwable t) {
229 LOG.warn("Request create node in topology for VBD was not stored to CONF DS. {}", nodeIid, t);
230 future.setException(new Exception("Cannot send request to VBD."));
239 public ListenableFuture<Void> removeBridgeDomainFromVppNode(@Nonnull String bridgeDomainName, NodeId vppNode) {
240 WriteTransaction wTx = dataProvder.newWriteOnlyTransaction();
241 InstanceIdentifier<Node> nodeIid =
242 VppIidFactory.getNodeIid(new TopologyKey(new TopologyId(bridgeDomainName)), new NodeKey(vppNode));
243 wTx.delete(LogicalDatastoreType.CONFIGURATION, nodeIid);
244 SettableFuture<Void> future = SettableFuture.create();
245 Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
248 public void onSuccess(Void result) {
249 DataTreeIdentifier<BridgeMember> bridgeMemberIid =
250 new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
251 nodeIid.augmentation(NodeVbridgeAugment.class).child(BridgeMember.class));
252 LOG.debug("Request delete node in topology for VBD was stored to CONF DS. {}", nodeIid);
253 new ListenableFutureSetter<>(dataProvder, future, bridgeMemberIid, ModificationType.DELETE);
257 public void onFailure(Throwable t) {
258 LOG.warn("Request delete node in topology for VBD was not stored to CONF DS. {}", nodeIid, t);
259 future.setException(new Exception("Cannot send request to VBD."));