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