BUG 5746 - Ovsdb QoS and Queue model enhancements
[ovsdb.git] / southbound / southbound-impl / src / main / java / org / opendaylight / ovsdb / southbound / ovsdb / transact / TerminationPointUpdateCommand.java
1 /*
2  * Copyright (c) 2015, 2016 Brocade Communications 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 package org.opendaylight.ovsdb.southbound.ovsdb.transact;
9
10 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
11
12 import java.util.Collection;
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Map.Entry;
18 import java.util.Set;
19 import java.util.concurrent.ExecutionException;
20
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.common.api.data.AsyncDataChangeEvent;
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.ovsdb.lib.error.SchemaVersionMismatchException;
27 import org.opendaylight.ovsdb.lib.notation.UUID;
28 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
29 import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
30 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
31 import org.opendaylight.ovsdb.schema.openvswitch.Port;
32 import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
33 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
34 import org.opendaylight.ovsdb.southbound.SouthboundProvider;
35 import org.opendaylight.ovsdb.utils.yang.YangUtils;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbPortInterfaceAttributes.VlanMode;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbQosRef;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QosEntries;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.Queues;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfd;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIds;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceLldp;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceOtherConfigs;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortExternalIds;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortOtherConfigs;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Trunks;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
54 import org.opendaylight.yangtools.yang.binding.DataObject;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 import com.google.common.base.Optional;
60 import com.google.common.collect.Sets;
61 import com.google.common.util.concurrent.CheckedFuture;
62
63 public class TerminationPointUpdateCommand implements TransactCommand {
64
65     private static final Logger LOG = LoggerFactory.getLogger(TerminationPointUpdateCommand.class);
66
67     @Override
68     public void execute(TransactionBuilder transaction, BridgeOperationalState state,
69                         AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> events) {
70         execute(transaction, state, TransactUtils.extractCreatedOrUpdated(events, OvsdbTerminationPointAugmentation.class));
71     }
72
73     @Override
74     public void execute(TransactionBuilder transaction, BridgeOperationalState state,
75                         Collection<DataTreeModification<Node>> modifications) {
76         execute(transaction, state,
77                 TransactUtils.extractCreatedOrUpdated(modifications, OvsdbTerminationPointAugmentation.class));
78     }
79
80     private void execute(TransactionBuilder transaction, BridgeOperationalState state,
81                          Map<InstanceIdentifier<OvsdbTerminationPointAugmentation>,
82                                  OvsdbTerminationPointAugmentation> createdOrUpdated) {
83         LOG.trace("TerminationPointUpdateCommand called");
84         for (Entry<InstanceIdentifier<OvsdbTerminationPointAugmentation>,
85                 OvsdbTerminationPointAugmentation> terminationPointEntry : createdOrUpdated.entrySet()) {
86             updateTerminationPoint(transaction, state, terminationPointEntry.getKey(), terminationPointEntry.getValue());
87         }
88     }
89
90     public void updateTerminationPoint(TransactionBuilder transaction, BridgeOperationalState state,
91                                        InstanceIdentifier<OvsdbTerminationPointAugmentation> iid,
92                                        OvsdbTerminationPointAugmentation terminationPoint) {
93         if (terminationPoint != null) {
94             LOG.debug("Received request to update termination point {}",
95                     terminationPoint.getName());
96
97             // Update interface
98             Interface ovsInterface =
99                     TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), Interface.class);
100             updateInterface(terminationPoint, ovsInterface);
101             Interface extraInterface = TyperUtils.getTypedRowWrapper(
102                     transaction.getDatabaseSchema(), Interface.class);
103             extraInterface.setName("");
104             transaction.add(op.update(ovsInterface)
105                     .where(extraInterface.getNameColumn().getSchema().opEqual(terminationPoint.getName()))
106                     .build());
107
108             TerminationPointCreateCommand.stampInstanceIdentifier(transaction,
109                     iid.firstIdentifierOf(OvsdbTerminationPointAugmentation.class), terminationPoint.getName());
110
111             // Update port
112             OvsdbBridgeAugmentation operBridge = state.getBridgeNode(iid).get().getAugmentation(OvsdbBridgeAugmentation.class);
113             Port port = TyperUtils.getTypedRowWrapper(
114                     transaction.getDatabaseSchema(), Port.class);
115             updatePort(terminationPoint, port, operBridge);
116             Port extraPort = TyperUtils.getTypedRowWrapper(
117                     transaction.getDatabaseSchema(), Port.class);
118             extraPort.setName("");
119             transaction.add(op.update(port)
120                     .where(extraPort.getNameColumn().getSchema().opEqual(terminationPoint.getName()))
121                     .build());
122         }
123     }
124
125     private void updateInterface(
126             final OvsdbTerminationPointAugmentation terminationPoint,
127             final Interface ovsInterface) {
128         updateOfPort(terminationPoint, ovsInterface);
129         updateOfPortRequest(terminationPoint, ovsInterface);
130         updateInterfaceOptions(terminationPoint, ovsInterface);
131         updateInterfaceOtherConfig(terminationPoint, ovsInterface);
132         updateInterfaceExternalIds(terminationPoint, ovsInterface);
133         updateInterfaceLldp(terminationPoint, ovsInterface);
134         updateInterfaceBfd(terminationPoint, ovsInterface);
135         updateInterfacePolicing(terminationPoint, ovsInterface);
136     }
137
138     private void updatePort(
139             final OvsdbTerminationPointAugmentation terminationPoint,
140             final Port port,
141             final OvsdbBridgeAugmentation operBridge) {
142
143         updatePortOtherConfig(terminationPoint, port);
144         updatePortVlanTag(terminationPoint, port);
145         updatePortVlanTrunk(terminationPoint, port);
146         updatePortVlanMode(terminationPoint, port);
147         updatePortExternalIds(terminationPoint, port);
148         updatePortQos(terminationPoint, port, operBridge);
149     }
150
151     private void updatePortQos(
152             final OvsdbTerminationPointAugmentation terminationPoint,
153             final Port port,
154             final OvsdbBridgeAugmentation operBridge) {
155
156         Set<UUID> uuidSet = Sets.newHashSet();
157
158         // First check if QosEntry is present and use that
159         if (terminationPoint.getQosEntry() != null && !terminationPoint.getQosEntry().isEmpty()) {
160             OvsdbQosRef qosRef = terminationPoint.getQosEntry().iterator().next().getQosRef();
161             Uri qosId = qosRef.getValue().firstKeyOf(QosEntries.class).getQosId();
162             OvsdbNodeAugmentation operNode = getOperNode(operBridge);
163             if (operNode != null && operNode.getQosEntries() != null &&
164                     !operNode.getQosEntries().isEmpty()) {
165                 for (QosEntries qosEntry : operNode.getQosEntries()) {
166                     if (qosEntry.getQosId().equals(qosId)) {
167                         uuidSet.add(new UUID(qosEntry.getQosUuid().getValue()));
168                     }
169                 }
170             }
171             if (uuidSet.size() == 0) {
172                 uuidSet.add(new UUID(SouthboundConstants.QOS_NAMED_UUID_PREFIX +
173                             TransactUtils.bytesToHexString(qosId.getValue().getBytes())));
174             }
175         } else {
176             // Second check if Qos is present and use that (deprecated)
177             // Do not bother to check if QosEntry and Qos are consistent if both are present
178             Uuid qosUuid = terminationPoint.getQos();
179             if (qosUuid != null) {
180                 uuidSet.add(new UUID(qosUuid.getValue()));
181             }
182         }
183         port.setQos(uuidSet);
184     }
185
186     private OvsdbNodeAugmentation getOperNode(final OvsdbBridgeAugmentation operBridge) {
187         @SuppressWarnings("unchecked")
188         InstanceIdentifier<Node> iidNode = (InstanceIdentifier<Node>)operBridge.getManagedBy().getValue();
189         OvsdbNodeAugmentation operNode = null;
190         ReadOnlyTransaction transaction = SouthboundProvider.getDb().newReadOnlyTransaction();
191         CheckedFuture<Optional<Node>, ReadFailedException> future =
192                 transaction.read(LogicalDatastoreType.OPERATIONAL, iidNode);
193         try {
194             Optional<Node> nodeOptional = future.get();
195             if (nodeOptional.isPresent()) {
196                 operNode = nodeOptional.get().getAugmentation(OvsdbNodeAugmentation.class);
197             }
198         } catch (InterruptedException | ExecutionException e) {
199             LOG.warn("Error reading from datastore", e);
200         }
201         return operNode;
202     }
203
204     private void updateOfPort(
205             final OvsdbTerminationPointAugmentation terminationPoint,
206             final Interface ovsInterface) {
207
208         Long ofPort = terminationPoint.getOfport();
209         if (ofPort != null) {
210             ovsInterface.setOpenFlowPort(Sets.newHashSet(ofPort));
211         }
212     }
213
214     private void updateOfPortRequest(
215             final OvsdbTerminationPointAugmentation terminationPoint,
216             final Interface ovsInterface) {
217
218         Integer ofPortRequest = terminationPoint.getOfportRequest();
219         if (ofPortRequest != null) {
220             ovsInterface.setOpenFlowPortRequest(Sets.newHashSet(ofPortRequest.longValue()));
221         }
222     }
223
224     private void updateInterfaceOptions(
225             final OvsdbTerminationPointAugmentation terminationPoint,
226             final Interface ovsInterface) {
227
228         //Configure optional input
229         if (terminationPoint.getOptions() != null) {
230             try {
231                 ovsInterface.setOptions(YangUtils.convertYangKeyValueListToMap(terminationPoint.getOptions(),
232                         Options::getOption, Options::getValue));
233             } catch (NullPointerException e) {
234                 LOG.warn("Incomplete OVSDB interface options", e);
235             }
236         }
237     }
238
239     private void updateInterfaceExternalIds(
240             final OvsdbTerminationPointAugmentation terminationPoint,
241             final Interface ovsInterface) {
242
243         List<InterfaceExternalIds> interfaceExternalIds =
244                 terminationPoint.getInterfaceExternalIds();
245         if (interfaceExternalIds != null && !interfaceExternalIds.isEmpty()) {
246             try {
247                 ovsInterface.setExternalIds(YangUtils.convertYangKeyValueListToMap(interfaceExternalIds,
248                         InterfaceExternalIds::getExternalIdKey, InterfaceExternalIds::getExternalIdValue));
249             } catch (NullPointerException e) {
250                 LOG.warn("Incomplete OVSDB interface external_ids", e);
251             }
252         }
253     }
254
255     private void updateInterfaceLldp(
256             final OvsdbTerminationPointAugmentation terminationPoint,
257             final Interface ovsInterface) {
258
259         try {
260             List<InterfaceLldp> interfaceLldpList =
261                     terminationPoint.getInterfaceLldp();
262             if (interfaceLldpList != null && !interfaceLldpList.isEmpty()) {
263                 try {
264                     ovsInterface.setLldp(YangUtils.convertYangKeyValueListToMap(interfaceLldpList,
265                             InterfaceLldp::getLldpKey, InterfaceLldp::getLldpValue));
266                 } catch (NullPointerException e) {
267                     LOG.warn("Incomplete OVSDB interface lldp", e);
268                 }
269             }
270         } catch (SchemaVersionMismatchException e) {
271             LOG.debug("lldp column for Interface Table unsupported for this version of ovsdb schema", e);
272         }
273     }
274
275     private void updateInterfaceOtherConfig(
276             final OvsdbTerminationPointAugmentation terminationPoint,
277             final Interface ovsInterface) {
278
279         List<InterfaceOtherConfigs> interfaceOtherConfigs =
280                 terminationPoint.getInterfaceOtherConfigs();
281         if (interfaceOtherConfigs != null && !interfaceOtherConfigs.isEmpty()) {
282             Map<String, String> otherConfigsMap = new HashMap<>();
283             for (InterfaceOtherConfigs interfaceOtherConfig : interfaceOtherConfigs) {
284                 otherConfigsMap.put(interfaceOtherConfig.getOtherConfigKey(),
285                         interfaceOtherConfig.getOtherConfigValue());
286             }
287             try {
288                 ovsInterface.setOtherConfig(otherConfigsMap);
289             } catch (NullPointerException e) {
290                 LOG.warn("Incomplete OVSDB interface other_config", e);
291             }
292         }
293     }
294
295     private void updateInterfaceBfd(
296             final OvsdbTerminationPointAugmentation terminationPoint,
297             final Interface ovsInterface) {
298
299         try {
300             List<InterfaceBfd> interfaceBfdList =
301                     terminationPoint.getInterfaceBfd();
302             if (interfaceBfdList != null && !interfaceBfdList.isEmpty()) {
303                 try {
304                     ovsInterface.setBfd(YangUtils.convertYangKeyValueListToMap(interfaceBfdList,
305                             InterfaceBfd::getBfdKey, InterfaceBfd::getBfdValue));
306                 } catch (NullPointerException e) {
307                     LOG.warn("Incomplete OVSDB interface bfd", e);
308                 }
309             }
310         } catch (SchemaVersionMismatchException e) {
311             LOG.debug("bfd column for Interface Table unsupported for this version of ovsdb schema", e);
312         }
313     }
314
315     private void updateInterfacePolicing(
316             final OvsdbTerminationPointAugmentation terminationPoint,
317             final Interface ovsInterface) {
318
319         Long ingressPolicingRate = terminationPoint.getIngressPolicingRate();
320         if (ingressPolicingRate != null) {
321             ovsInterface.setIngressPolicingRate(ingressPolicingRate);
322         }
323         Long ingressPolicingBurst = terminationPoint.getIngressPolicingBurst();
324         if (ingressPolicingBurst != null) {
325             ovsInterface.setIngressPolicingBurst(ingressPolicingBurst);
326         }
327     }
328
329     private void updatePortExternalIds(
330             final OvsdbTerminationPointAugmentation terminationPoint,
331             final Port port) {
332
333         List<PortExternalIds> portExternalIds = terminationPoint.getPortExternalIds();
334         if (portExternalIds != null && !portExternalIds.isEmpty()) {
335             try {
336                 port.setExternalIds(YangUtils.convertYangKeyValueListToMap(portExternalIds,
337                         PortExternalIds::getExternalIdKey, PortExternalIds::getExternalIdValue));
338             } catch (NullPointerException e) {
339                 LOG.warn("Incomplete OVSDB port external_ids", e);
340             }
341         }
342     }
343
344     private void updatePortVlanTag(
345             final OvsdbTerminationPointAugmentation terminationPoint,
346             final Port port) {
347
348         if (terminationPoint.getVlanTag() != null) {
349             Set<Long> vlanTag = new HashSet<>();
350             vlanTag.add(terminationPoint.getVlanTag().getValue().longValue());
351             port.setTag(vlanTag);
352         }
353     }
354
355     private void updatePortVlanTrunk(
356             final OvsdbTerminationPointAugmentation terminationPoint,
357             final Port port) {
358
359         if (terminationPoint.getTrunks() != null && terminationPoint.getTrunks().size() > 0) {
360             Set<Long> portTrunks = new HashSet<>();
361             List<Trunks> modelTrunks = terminationPoint.getTrunks();
362             for (Trunks trunk : modelTrunks) {
363                 if (trunk.getTrunk() != null) {
364                     portTrunks.add(trunk.getTrunk().getValue().longValue());
365                 }
366             }
367             port.setTrunks(portTrunks);
368         }
369     }
370
371     private void updatePortVlanMode(
372             final OvsdbTerminationPointAugmentation terminationPoint,
373             final Port port) {
374         if (terminationPoint.getVlanMode() != null) {
375             Set<String> portVlanMode = new HashSet<>();
376             VlanMode modelVlanMode = terminationPoint.getVlanMode();
377             portVlanMode.add(SouthboundConstants.VLANMODES.values()[modelVlanMode.getIntValue() - 1].getMode());
378             port.setVlanMode(portVlanMode);
379         }
380     }
381
382     private void updatePortOtherConfig(
383             final OvsdbTerminationPointAugmentation terminationPoint,
384             final Port ovsPort) {
385         List<PortOtherConfigs> portOtherConfigs =
386                 terminationPoint.getPortOtherConfigs();
387         if (portOtherConfigs != null && !portOtherConfigs.isEmpty()) {
388             try {
389                 ovsPort.setOtherConfig(YangUtils.convertYangKeyValueListToMap(portOtherConfigs,
390                         PortOtherConfigs::getOtherConfigKey, PortOtherConfigs::getOtherConfigValue));
391             } catch (NullPointerException e) {
392                 LOG.warn("Incomplete OVSDB port other_config", e);
393             }
394         }
395     }
396
397 }