521bc08aed3e630e61f18230b15c4f74bd158544
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / transact / PhysicalPortUpdateCommand.java
1 /*
2  * Copyright © 2015, 2017 China Telecom Beijing Research Institute 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.ovsdb.hwvtepsouthbound.transact;
10
11 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
12
13 import com.google.common.collect.Lists;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Map.Entry;
21 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
22 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
23 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
24 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
25 import org.opendaylight.ovsdb.lib.notation.UUID;
26 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
27 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalPort;
28 import org.opendaylight.ovsdb.utils.mdsal.utils.TransactionType;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalPortAugmentation;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindings;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindingsKey;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 public class PhysicalPortUpdateCommand extends AbstractTransactCommand {
42     private static final Logger LOG = LoggerFactory.getLogger(PhysicalPortUpdateCommand.class);
43     private static final VlanBindingsUnMetDependencyGetter DEPENDENCY_GETTER = new VlanBindingsUnMetDependencyGetter();
44
45     public PhysicalPortUpdateCommand(final HwvtepOperationalState state,
46             final Collection<DataTreeModification<Node>> changes) {
47         super(state, changes);
48     }
49
50     @Override
51     public void execute(final TransactionBuilder transaction) {
52         Map<InstanceIdentifier<Node>, List<TerminationPoint>> createds =
53                 extractCreated(getChanges(),TerminationPoint.class);
54         if (!createds.isEmpty()) {
55             for (Entry<InstanceIdentifier<Node>, List<TerminationPoint>> created:
56                 createds.entrySet()) {
57                 updatePhysicalPort(transaction,  created.getKey(), created.getValue());
58             }
59         }
60         Map<InstanceIdentifier<Node>, List<TerminationPoint>> updateds =
61                 extractUpdatedPorts(getChanges(), TerminationPoint.class);
62         if (!updateds.isEmpty()) {
63             for (Entry<InstanceIdentifier<Node>, List<TerminationPoint>> updated:
64                 updateds.entrySet()) {
65                 updatePhysicalPort(transaction,  updated.getKey(), updated.getValue());
66             }
67         }
68     }
69
70     public void updatePhysicalPort(final TransactionBuilder transaction,
71                                    final InstanceIdentifier<Node> psNodeiid,
72                                    final List<TerminationPoint> listPort) {
73         //Get physical switch which the port belong to: in operation DS or new created
74         for (TerminationPoint tp : listPort) {
75             HwvtepPhysicalPortAugmentation port = tp.augmentation(HwvtepPhysicalPortAugmentation.class);
76             LOG.debug("Creating a physical port named: {}", port.getHwvtepNodeName().getValue());
77             InstanceIdentifier<TerminationPoint> key = getTpIid(psNodeiid, port.getHwvtepNodeName().getValue());
78
79             getOperationalState().getDeviceInfo().updateConfigData(TerminationPoint.class, key, tp);
80             HwvtepDeviceInfo.DeviceData deviceOperdata = getDeviceInfo().getDeviceOperData(TerminationPoint.class, key);
81             if (deviceOperdata == null || deviceOperdata.getData() == null) {
82                 LOG.error("Updated the device oper cache for port from actual device {}", key);
83                 deviceOperdata = super.fetchDeviceData(TerminationPoint.class, key);
84             }
85             if (deviceOperdata == null || deviceOperdata.getData() == null) {
86                 //create a physical port always happens from device
87                 LOG.error("Physical port {} not present in oper datastore", port.getHwvtepNodeName().getValue());
88             } else {
89                 PhysicalPort physicalPort = transaction.getTypedRowWrapper(PhysicalPort.class);
90                 physicalPort.setName(port.getHwvtepNodeName().getValue());
91                 setVlanBindings(psNodeiid, physicalPort, tp, transaction);
92                 setDescription(physicalPort, port);
93                 String existingPhysicalPortName = port.getHwvtepNodeName().getValue();
94                 PhysicalPort extraPhyscialPort = transaction.getTypedRowWrapper(PhysicalPort.class);
95                 extraPhyscialPort.setName("");
96                 LOG.trace("execute: updating physical port: {}", physicalPort);
97                 transaction.add(op.update(physicalPort)
98                         .where(extraPhyscialPort.getNameColumn().getSchema().opEqual(existingPhysicalPortName))
99                         .build());
100                 transaction.add(op.comment("Physical Port: Updating " + existingPhysicalPortName));
101                 updateControllerTxHistory(TransactionType.UPDATE, physicalPort);
102             }
103         }
104     }
105
106     private static void setDescription(final PhysicalPort physicalPort,
107             final HwvtepPhysicalPortAugmentation inputPhysicalPort) {
108         if (inputPhysicalPort.getHwvtepNodeDescription() != null) {
109             physicalPort.setDescription(inputPhysicalPort.getHwvtepNodeDescription());
110         }
111     }
112
113     private void setVlanBindings(final InstanceIdentifier<Node> psNodeiid,
114                                  final PhysicalPort physicalPort,
115                                  final TerminationPoint tp,
116                                  final TransactionBuilder transaction) {
117         HwvtepPhysicalPortAugmentation inputPhysicalPort = tp.augmentation(HwvtepPhysicalPortAugmentation.class);
118         if (inputPhysicalPort.getVlanBindings() != null) {
119             //get UUID by LogicalSwitchRef
120             Map<Long, UUID> bindingMap = new HashMap<>();
121             for (VlanBindings vlanBinding: inputPhysicalPort.getVlanBindings()) {
122                 InstanceIdentifier<VlanBindings> vlanIid = getVlanBindingIid(psNodeiid, physicalPort, vlanBinding);
123                 @SuppressWarnings("unchecked")
124                 InstanceIdentifier<LogicalSwitches> lswitchIid =
125                         (InstanceIdentifier<LogicalSwitches>) vlanBinding.getLogicalSwitchRef().getValue();
126
127                 Map inTransitDependencies = DEPENDENCY_GETTER.getInTransitDependencies(
128                         getOperationalState(), vlanBinding);
129                 Map configDependencies = DEPENDENCY_GETTER.getUnMetConfigDependencies(
130                         getOperationalState(), vlanBinding);
131
132                 if (!HwvtepSouthboundUtil.isEmptyMap(configDependencies)) {
133                     createConfigWaitJob(psNodeiid, tp,
134                             vlanBinding, configDependencies, vlanIid);
135                     continue;
136                 }
137                 if (!HwvtepSouthboundUtil.isEmptyMap(inTransitDependencies)) {
138                     createOperWaitingJob(psNodeiid, tp,
139                             vlanBinding, inTransitDependencies, vlanIid);
140                     continue;
141                 }
142
143                 UUID lsUUid = TransactUtils.getLogicalSwitchUUID(transaction, getOperationalState(), lswitchIid);
144                 if (lsUUid == null) {
145                     LOG.error("Could not get the logical switch uuid for {}", vlanBinding);
146                     continue;
147                 }
148                 bindingMap.put(vlanBinding.getVlanIdKey().getValue().longValue(), lsUUid);
149             }
150             physicalPort.setVlanBindings(bindingMap);
151         }
152     }
153
154     private void createOperWaitingJob(final InstanceIdentifier<Node> psNodeiid,
155                                       final TerminationPoint inputPhysicalPort,
156                                       final VlanBindings vlanBinding,
157                                       final Map inTransitDependencies,
158                                       final InstanceIdentifier<VlanBindings> vlanIid) {
159
160         DependentJob<VlanBindings> opWaitingJob = new DependentJob.OpWaitingJob<VlanBindings>(
161                 vlanIid, vlanBinding, inTransitDependencies) {
162             @Override
163             public void onDependencyResolved(final HwvtepOperationalState operationalState,
164                                              final TransactionBuilder transactionBuilder) {
165                 hwvtepOperationalState = operationalState;
166                 deviceTransaction = transactionBuilder;
167                 updatePhysicalPort(transactionBuilder, psNodeiid, Lists.newArrayList(inputPhysicalPort));
168             }
169         };
170         getDeviceInfo().addJobToQueue(opWaitingJob);
171     }
172
173     private void createConfigWaitJob(final InstanceIdentifier<Node> psNodeiid,
174                                      final TerminationPoint inputPhysicalPort,
175                                      final VlanBindings vlanBinding,
176                                      final Map configDependencies,
177                                      final InstanceIdentifier<VlanBindings> vlanIid) {
178
179         DependentJob<VlanBindings> configWaitingJob = new DependentJob.ConfigWaitingJob<VlanBindings>(
180                 vlanIid, vlanBinding, configDependencies) {
181             @Override
182             public void onDependencyResolved(final HwvtepOperationalState operationalState,
183                                              final TransactionBuilder transactionBuilder) {
184                 hwvtepOperationalState = operationalState;
185                 deviceTransaction = transactionBuilder;
186                 updatePhysicalPort(transactionBuilder, psNodeiid, Lists.newArrayList(inputPhysicalPort));
187             }
188         };
189         getDeviceInfo().addJobToQueue(configWaitingJob);
190     }
191
192     private static InstanceIdentifier<TerminationPoint> getTpIid(final InstanceIdentifier<Node> psNodeiid,
193                                                                  final String portName) {
194         return psNodeiid.child(TerminationPoint.class, new TerminationPointKey(new TpId(portName)));
195     }
196
197     private static InstanceIdentifier<VlanBindings> getVlanBindingIid(final InstanceIdentifier<Node> psNodeiid,
198                                                                       final PhysicalPort physicalPort,
199                                                                       final VlanBindings vlanBinding) {
200         return getTpIid(psNodeiid, physicalPort.getName())
201                 .augmentation(HwvtepPhysicalPortAugmentation.class)
202                 .child(VlanBindings.class, new VlanBindingsKey(vlanBinding.getVlanIdKey()));
203     }
204
205     static class VlanBindingsUnMetDependencyGetter extends UnMetDependencyGetter<VlanBindings> {
206
207         @Override
208         public List<InstanceIdentifier<?>> getLogicalSwitchDependencies(final VlanBindings data) {
209             if (data == null) {
210                 return Collections.emptyList();
211             }
212             return Collections.singletonList(data.getLogicalSwitchRef().getValue());
213         }
214
215         @Override
216         public List<InstanceIdentifier<?>> getTerminationPointDependencies(final VlanBindings data) {
217             return Collections.emptyList();
218         }
219     }
220
221     private static Map<InstanceIdentifier<Node>, List<TerminationPoint>> extractCreated(
222             final Collection<DataTreeModification<Node>> changes, final Class<TerminationPoint> class1) {
223         Map<InstanceIdentifier<Node>, List<TerminationPoint>> result = new HashMap<>();
224         if (changes != null && !changes.isEmpty()) {
225             for (DataTreeModification<Node> change : changes) {
226                 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
227                 final DataObjectModification<Node> mod = change.getRootNode();
228                 Node created = TransactUtils.getCreated(mod);
229                 if (created != null) {
230                     List<TerminationPoint> portListUpdated = new ArrayList<>();
231                     if (created.getTerminationPoint() != null) {
232                         for (TerminationPoint tp : created.getTerminationPoint()) {
233                             HwvtepPhysicalPortAugmentation hppAugmentation =
234                                     tp.augmentation(HwvtepPhysicalPortAugmentation.class);
235                             if (hppAugmentation != null) {
236                                 portListUpdated.add(tp);
237                             }
238                         }
239                     }
240                     result.put(key, portListUpdated);
241                 }
242             }
243         }
244         return result;
245     }
246
247     private static Map<InstanceIdentifier<Node>, List<TerminationPoint>> extractUpdatedPorts(
248             final Collection<DataTreeModification<Node>> changes, final Class<TerminationPoint> class1) {
249         Map<InstanceIdentifier<Node>, List<TerminationPoint>> result = new HashMap<>();
250         if (changes != null && !changes.isEmpty()) {
251             for (DataTreeModification<Node> change : changes) {
252                 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
253                 final DataObjectModification<Node> mod = change.getRootNode();
254                 Node updated = TransactUtils.getUpdated(mod);
255                 Node before = mod.getDataBefore();
256                 if (updated != null && before != null) {
257                     List<TerminationPoint> portListUpdated = new ArrayList<>();
258                     List<TerminationPoint> portListBefore = new ArrayList<>();
259                     if (updated.getTerminationPoint() != null) {
260                         for (TerminationPoint tp : updated.getTerminationPoint()) {
261                             HwvtepPhysicalPortAugmentation hppAugmentation =
262                                     tp.augmentation(HwvtepPhysicalPortAugmentation.class);
263                             if (hppAugmentation != null) {
264                                 portListUpdated.add(tp);
265                             }
266                         }
267                     }
268                     if (before.getTerminationPoint() != null) {
269                         for (TerminationPoint tp : before.getTerminationPoint()) {
270                             HwvtepPhysicalPortAugmentation hppAugmentation =
271                                     tp.augmentation(HwvtepPhysicalPortAugmentation.class);
272                             if (hppAugmentation != null) {
273                                 portListBefore.add(tp);
274                             }
275                         }
276                     }
277                     portListUpdated.removeAll(portListBefore);
278                     result.put(key, portListUpdated);
279                 }
280             }
281         }
282         return result;
283     }
284
285     protected String getKeyStr(InstanceIdentifier iid) {
286         try {
287             return ((TerminationPoint)iid.firstKeyOf(TerminationPoint.class)).getTpId().getValue();
288         } catch (ClassCastException exp) {
289             LOG.error("Error in getting the TerminationPoint id ", exp);
290         }
291         return super.getKeyStr(iid);
292     }
293
294 }