Add VPP to bridge domain.
[honeycomb.git] / vbd / impl / src / main / java / io / fd / honeycomb / vbd / impl / BridgeDomain.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 io.fd.honeycomb.vbd.impl;
10
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import java.util.Collection;
14 import javax.annotation.concurrent.GuardedBy;
15 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
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.MountPoint;
23 import org.opendaylight.controller.md.sal.binding.api.MountPointService;
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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugment;
31 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
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.TopologyId;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.node.attributes.SupportingNode;
39 import org.opendaylight.yangtools.concepts.ListenerRegistration;
40 import org.opendaylight.yangtools.yang.binding.DataObject;
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
42 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 /**
47  * Implementation of a single Virtual Bridge Domain. It is bound to a particular network topology instance, manages
48  * bridge members and projects state into the operational data store.
49  */
50 final class BridgeDomain implements DataTreeChangeListener<Topology> {
51     private static final Logger LOG = LoggerFactory.getLogger(BridgeDomain.class);
52     private final KeyedInstanceIdentifier<Topology, TopologyKey> topology;
53     @GuardedBy("this")
54
55     private final BindingTransactionChain chain;
56     private final ListenerRegistration<?> reg;
57     private final MountPointService mountService;
58     private TopologyVbridgeAugment config;
59     private final String bridgeDomainName;
60     private final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain> iiBridgeDomainOnVPP;
61
62     private BridgeDomain(final DataBroker dataBroker, final MountPointService mountService, final KeyedInstanceIdentifier<Topology, TopologyKey> topology,
63             final BindingTransactionChain chain) {
64         this.topology = Preconditions.checkNotNull(topology);
65         this.chain = Preconditions.checkNotNull(chain);
66         this.mountService = mountService;
67
68         this.bridgeDomainName = topology.getKey().getTopologyId().getValue();
69         this.iiBridgeDomainOnVPP = InstanceIdentifier.create(Vpp.class)
70                 .child(BridgeDomains.class)
71                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain.class, new BridgeDomainKey(bridgeDomainName));
72
73         reg = dataBroker.registerDataTreeChangeListener(
74             new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, topology), this);
75     }
76
77     static BridgeDomain create(final DataBroker dataBroker,
78                                MountPointService mountService, final KeyedInstanceIdentifier<Topology, TopologyKey> topology, final BindingTransactionChain chain) {
79
80         LOG.debug("Wiping operational state of {}", topology);
81
82         final WriteTransaction tx = chain.newWriteOnlyTransaction();
83         tx.delete(LogicalDatastoreType.OPERATIONAL, topology);
84         tx.submit();
85
86         return new BridgeDomain(dataBroker, mountService, topology, chain);
87     }
88
89     synchronized void forceStop() {
90         LOG.info("Bridge domain {} for {} going down", this, topology);
91         reg.close();
92         chain.close();
93         LOG.info("Bridge domain {} for {} is down", this, topology);
94     }
95
96     synchronized void stop() {
97         LOG.debug("Bridge domain {} for {} shutting down", this, topology);
98
99         final WriteTransaction tx = chain.newWriteOnlyTransaction();
100         tx.delete(LogicalDatastoreType.OPERATIONAL, topology);
101         tx.submit();
102         chain.close();
103     }
104
105     @Override
106     public synchronized void onDataTreeChanged(final Collection<DataTreeModification<Topology>> changes) {
107         for (DataTreeModification<Topology> c : changes) {
108             LOG.debug("Domain {} for {} processing change {}", this, topology, c);
109
110             final DataObjectModification<Topology> mod = c.getRootNode();
111             switch (mod.getModificationType()) {
112                 case DELETE:
113                     LOG.debug("Topology {} deleted, expecting shutdown", topology);
114                     break;
115                 case SUBTREE_MODIFIED:
116                     // First check if the configuration has changed
117                     final DataObjectModification<TopologyVbridgeAugment> newConfig = mod.getModifiedAugmentation(TopologyVbridgeAugment.class);
118                     if (newConfig != null) {
119                         if (newConfig.getModificationType() != ModificationType.DELETE) {
120                             LOG.debug("Topology {} modified configuration {}", topology, newConfig);
121                             updateConfiguration(newConfig);
122                         } else {
123                             // FIXME: okay, what can we do about this one?
124                             LOG.error("Topology {} configuration deleted, good luck!", topology);
125                         }
126                     }
127
128                     for (DataObjectModification<? extends DataObject> child : mod.getModifiedChildren()) {
129                         LOG.debug("Topology {} modified child {}", topology, child);
130
131                         if (Node.class.isAssignableFrom(child.getDataType())) {
132                             modifyNode((DataObjectModification<Node>) child, newConfig.getDataAfter());
133                         }
134                     }
135
136                     break;
137                 case WRITE:
138                     final Topology data = mod.getDataAfter();
139
140                     // Read configuration
141                     final TopologyVbridgeAugment config = data.getAugmentation(TopologyVbridgeAugment.class);
142                     if (config != null) {
143                         setConfiguration(config);
144                     } else {
145                         LOG.error("Topology {} has no configuration, good luck!", topology);
146                     }
147
148                     // FIXME: deal with nodes
149
150                     break;
151                 default:
152                     LOG.warn("Unhandled topology modification {}", mod);
153                     break;
154             }
155         }
156     }
157
158     private void modifyNode(final DataObjectModification<Node> child, final TopologyVbridgeAugment topologyVbridgeAugment) {
159         switch (child.getModificationType()) {
160             case DELETE:
161                 LOG.debug("Topology {} node {} deleted", topology, child.getIdentifier());
162                 // FIXME: do something
163                 break;
164             case SUBTREE_MODIFIED:
165                 LOG.debug("Topology {} node {} modified", topology, child.getIdentifier());
166                 // FIXME: do something
167                 break;
168             case WRITE:
169                 LOG.debug("Topology {} node {} created", topology, child.getIdentifier());
170                 createNode(child.getDataAfter(), topologyVbridgeAugment);
171                 break;
172             default:
173                 LOG.warn("Unhandled node modification {} in topology {}", child, topology);
174                 break;
175         }
176     }
177
178     private void createNode(final Node node, final TopologyVbridgeAugment topologyVbridgeAugment) {
179         for (SupportingNode supportingNode : node.getSupportingNode()) {
180             final NodeId nodeMount = supportingNode.getNodeRef();
181             final TopologyId topologyMount = supportingNode.getTopologyRef();
182
183             final KeyedInstanceIdentifier<Node, NodeKey> iiToMount = InstanceIdentifier
184                     .create(NetworkTopology.class)
185                     .child(Topology.class, new TopologyKey(topologyMount))
186                     .child(Node.class, new NodeKey(nodeMount));
187             final Optional<MountPoint> vppMountOption = mountService.getMountPoint(iiToMount);
188             if (vppMountOption.isPresent()) {
189                 final MountPoint vppMount = vppMountOption.get();
190                 addVppToBridgeDomain(topologyVbridgeAugment, vppMount);
191             }
192         }
193     }
194
195     private void addVppToBridgeDomain(TopologyVbridgeAugment topologyVbridgeAugment, MountPoint vppMount) {
196         final Optional<DataBroker> dataBrokerOpt = vppMount.getService(DataBroker.class);
197         if (dataBrokerOpt.isPresent()) {
198             final DataBroker vppDataBroker = dataBrokerOpt.get();
199             final WriteTransaction wTx = vppDataBroker.newWriteOnlyTransaction();
200             wTx.put(LogicalDatastoreType.OPERATIONAL, iiBridgeDomainOnVPP, prepareNewBridgeDomainData(topologyVbridgeAugment));
201             wTx.submit();
202         }
203     }
204
205     private org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain
206         prepareNewBridgeDomainData(TopologyVbridgeAugment topologyVbridgeAugment) {
207             final BridgeDomainBuilder bridgeDomainBuilder = new BridgeDomainBuilder(topologyVbridgeAugment);
208             bridgeDomainBuilder.setName(topology.getKey().getTopologyId().getValue());
209             return bridgeDomainBuilder.build();
210     }
211
212     private void setConfiguration(final TopologyVbridgeAugment config) {
213         LOG.debug("Topology {} configuration set to {}", topology, config);
214
215         this.config = config;
216     }
217
218     @GuardedBy("this")
219     private void updateConfiguration(final DataObjectModification<TopologyVbridgeAugment> mod) {
220         LOG.debug("Topology {} configuration changed", topology);
221
222         // FIXME: do something smarter
223         setConfiguration(mod.getDataAfter());
224     }
225 }