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