Merge "Fix so that operational store correctly removes bridge-other-configs"
[ovsdb.git] / southbound / southbound-impl / src / main / java / org / opendaylight / ovsdb / southbound / transactions / md / OvsdbPortUpdateCommand.java
1 /*
2  * Copyright (c) 2014 Intel Corp. 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.southbound.transactions.md;
10
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17
18 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
21 import org.opendaylight.ovsdb.lib.message.TableUpdates;
22 import org.opendaylight.ovsdb.lib.notation.Column;
23 import org.opendaylight.ovsdb.lib.notation.UUID;
24 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
25 import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
26 import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
27 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
28 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
29 import org.opendaylight.ovsdb.schema.openvswitch.Port;
30 import org.opendaylight.ovsdb.southbound.OvsdbClientKey;
31 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
32 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeName;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbPortInterfaceAttributes;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIds;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIdsBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceOtherConfigs;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceOtherConfigsBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortExternalIds;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortExternalIdsBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortOtherConfigs;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortOtherConfigsBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Trunks;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.TrunksBuilder;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62
63 import com.google.common.base.Optional;
64
65 public class OvsdbPortUpdateCommand extends AbstractTransactionCommand {
66     private static final Logger LOG = LoggerFactory.getLogger(OvsdbPortUpdateCommand.class);
67
68     public OvsdbPortUpdateCommand(OvsdbClientKey key, TableUpdates updates,
69             DatabaseSchema dbSchema) {
70         super(key, updates, dbSchema);
71     }
72
73     @Override
74     public void execute(ReadWriteTransaction transaction) {
75         String bridgeName = null;
76         Collection<Port> portUpdatedRows = TyperUtils.extractRowsUpdated(
77                 Port.class, getUpdates(), getDbSchema()).values();
78         Collection<Bridge> bridgeUpdatedRows = TyperUtils.extractRowsUpdated(
79                 Bridge.class, getUpdates(), getDbSchema()).values();
80         for (Bridge bridge : bridgeUpdatedRows) {
81             Iterator<UUID> bridgePorts = bridge.getPortsColumn().getData()
82                     .iterator();
83             while (bridgePorts.hasNext()) {
84                 UUID portUUID = bridgePorts.next();
85                 for (Port port : portUpdatedRows) {
86                     if (portUUID.equals(port.getUuid())) {
87                         bridgeName = bridge.getName();
88                         NodeId bridgeId = SouthboundMapper.createManagedNodeId(
89                                 getKey(), new OvsdbBridgeName(bridgeName));
90                         final InstanceIdentifier<Node> nodePath = SouthboundMapper
91                                 .createInstanceIdentifier(bridgeId);
92                         Optional<Node> node = readNode(transaction, nodePath);
93                         if (node.isPresent()) {
94                             NodeBuilder nodeBuilder = buildNode(node, bridgeId, bridge, port);
95                             transaction.merge(LogicalDatastoreType.OPERATIONAL,
96                                     nodePath, nodeBuilder.build());
97                         }
98                     }
99                 }
100             }
101         }
102     }
103
104     private Optional<Node> readNode(final ReadWriteTransaction transaction, final InstanceIdentifier<Node> nodePath) {
105         Optional<Node> node = Optional.absent();
106         try {
107             node = transaction.read(
108                     LogicalDatastoreType.OPERATIONAL, nodePath)
109                     .checkedGet();
110         } catch (final ReadFailedException e) {
111             LOG.warn("Read Operational/DS for Node fail! {}",
112                     nodePath, e);
113         }
114         return node;
115     }
116
117     private NodeBuilder buildNode(final Optional<Node> node, final NodeId bridgeId, final Bridge bridge,
118             final Port port) {
119         NodeBuilder nodeBuilder = new NodeBuilder();
120         nodeBuilder.setNodeId(bridgeId);
121         List<TerminationPoint> tpList = buildTpList(bridge, port);
122         nodeBuilder.setTerminationPoint(tpList);
123         nodeBuilder.addAugmentation(
124                 OvsdbBridgeAugmentation.class,
125                 node.get().getAugmentation(
126                         OvsdbBridgeAugmentation.class));
127         return nodeBuilder;
128     }
129
130     private List<TerminationPoint> buildTpList(final Bridge bridge, final Port port) {
131         List<TerminationPoint> tpList = new ArrayList<TerminationPoint>();
132         TerminationPointBuilder entry = new TerminationPointBuilder();
133         entry.setTpId(new TpId(port.getName()));
134         OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder =
135                 new OvsdbTerminationPointAugmentationBuilder();
136         ovsdbTerminationPointBuilder
137                 .setName(port.getName());
138         ovsdbTerminationPointBuilder.setPortUuid(new Uuid(
139                 port.getUuid().toString()));
140         updatePort(port, ovsdbTerminationPointBuilder);
141         updateInterfaces(port, bridge, ovsdbTerminationPointBuilder);
142         entry.addAugmentation(
143                 OvsdbTerminationPointAugmentation.class,
144                 ovsdbTerminationPointBuilder.build());
145         tpList.add(entry.build());
146         return tpList;
147     }
148
149     private void updateInterfaces(final Port port, final Bridge bridge,
150             final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
151
152         Column<GenericTableSchema, Set<UUID>> iface = port.getInterfacesColumn();
153         Set<UUID> ifUuid = iface.getData();
154         Collection<Interface> ifUpdateRows = TyperUtils.extractRowsUpdated(
155                 Interface.class, getUpdates(),  getDbSchema()).values();
156         updateInterfaces(ifUuid, ifUpdateRows, bridge, ovsdbTerminationPointBuilder);
157     }
158
159     private void updateInterfaces(final Set<UUID> ifUuid, final Collection<Interface> ifUpdateRows,
160             final Bridge bridge, final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
161
162         for (UUID ifIter : ifUuid) {
163             for (Interface interfIter : ifUpdateRows) {
164                 Column<GenericTableSchema, String> typeColumn = interfIter.getTypeColumn();
165                 String type = typeColumn.getData();
166                 if ((interfIter.getUuid()).equals(ifIter)) {
167                     updateInterface(interfIter, bridge, type, ovsdbTerminationPointBuilder);
168                     break;
169                 }
170             }
171         }
172     }
173
174     private void updatePort(final Port port,
175             final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
176
177         updateVlan(port, ovsdbTerminationPointBuilder);
178         updateVlanTrunks(port, ovsdbTerminationPointBuilder);
179         updateVlanMode(port, ovsdbTerminationPointBuilder);
180         updatePortExternalIds(port, ovsdbTerminationPointBuilder);
181         updatePortOtherConfig(port, ovsdbTerminationPointBuilder);
182     }
183
184     private void updateInterface(final Interface interf,
185             final Bridge bridge, final String type,
186             final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
187
188         ovsdbTerminationPointBuilder.setInterfaceUuid(
189                 new Uuid(interf.getUuid().toString()));
190         ovsdbTerminationPointBuilder.setInterfaceType(
191                 SouthboundMapper.createInterfaceType(type));
192         updateOfPort(interf, bridge, ovsdbTerminationPointBuilder);
193         updateOfPortRequest(interf, bridge, ovsdbTerminationPointBuilder);
194         updateInterfaceExternalIds(interf, ovsdbTerminationPointBuilder);
195         updateOptions(interf, ovsdbTerminationPointBuilder);
196         updateInterfaceOtherConfig(interf, ovsdbTerminationPointBuilder);
197     }
198
199     private void updateVlan(final Port port,
200             final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
201
202         Collection<Long> vlanId = port.getTagColumn().getData();
203         if (vlanId.size() > 0) {
204             Iterator<Long> itr = vlanId.iterator();
205             // There are no loops here, just get the first element.
206             int id = itr.next().intValue();
207             ovsdbTerminationPointBuilder.setVlanTag(new VlanId(id));
208         }
209     }
210
211     private void updateVlanTrunks(final Port port,
212             final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
213
214         Set<Long> portTrunks = port.getTrunksColumn().getData();
215         List<Trunks> modelTrunks = new ArrayList<Trunks>();
216         if (!portTrunks.isEmpty()) {
217             for (Long trunk: portTrunks) {
218                 if (trunk != null) {
219                     modelTrunks.add(new TrunksBuilder()
220                         .setTrunk(new VlanId(trunk.intValue())).build());
221                 }
222             }
223             ovsdbTerminationPointBuilder.setTrunks(modelTrunks);
224         }
225     }
226
227     private void updateVlanMode(final Port port,
228             final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
229
230         Collection<String> vlanMode = port.getVlanModeColumn().getData();
231         if (!vlanMode.isEmpty()) {
232             Iterator<String> itr = vlanMode.iterator();
233             String vlanType = itr.next();
234             if (vlanType.equals(SouthboundConstants.VLANMODES.ACCESS.getMode())) {
235                 ovsdbTerminationPointBuilder
236                     .setVlanMode(OvsdbPortInterfaceAttributes.VlanMode.Access);
237             } else if (vlanType.equals(SouthboundConstants.VLANMODES.NATIVE_TAGGED.getMode())) {
238                 ovsdbTerminationPointBuilder
239                     .setVlanMode(OvsdbPortInterfaceAttributes.VlanMode.NativeTagged);
240             } else if (vlanType.equals(SouthboundConstants.VLANMODES.NATIVE_UNTAGGED.getMode())) {
241                 ovsdbTerminationPointBuilder
242                     .setVlanMode(OvsdbPortInterfaceAttributes.VlanMode.NativeUntagged);
243             } else if (vlanType.equals(SouthboundConstants.VLANMODES.TRUNK.getMode())) {
244                 ovsdbTerminationPointBuilder
245                     .setVlanMode(OvsdbPortInterfaceAttributes.VlanMode.Trunk);
246             } else {
247                 LOG.debug("Invalid vlan mode {}.", vlanType);
248             }
249         }
250     }
251
252     private void updateOfPort(final Interface interf,
253             final Bridge bridge,
254             final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
255
256         Set<Long> ofPorts = interf.getOpenFlowPortColumn().getData();
257         if (ofPorts != null && !ofPorts.isEmpty()) {
258             Iterator<Long> ofPortsIter = ofPorts.iterator();
259             long ofPort = ofPortsIter.next();
260             if (ofPort >= 0) {
261                 ovsdbTerminationPointBuilder
262                     .setOfport(ofPort);
263             } else {
264                 LOG.debug("Received negative value for ofPort from ovsdb for {} {} {}",
265                         bridge.getName(), interf.getName(),ofPort);
266             }
267         }
268     }
269
270     private void updateOfPortRequest(final Interface interf,
271             final Bridge bridge,
272             final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
273
274         Set<Long> ofPortRequests = interf
275                 .getOpenFlowPortRequestColumn().getData();
276         if (ofPortRequests != null && !ofPortRequests.isEmpty()) {
277             Iterator<Long> ofPortRequestsIter = ofPortRequests.iterator();
278             int ofPort = ofPortRequestsIter.next().intValue();
279             if (ofPort >= 0) {
280                 ovsdbTerminationPointBuilder
281                     .setOfportRequest(ofPort);
282             } else {
283                 LOG.debug("Received negative value for ofPort from ovsdb for {} {} {}",
284                         bridge.getName(), interf.getName(),ofPort);
285             }
286         }
287     }
288
289     private void updateInterfaceExternalIds(final Interface interf,
290             final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
291
292         Map<String, String> interfaceExternalIds =
293                 interf.getExternalIdsColumn().getData();
294         if (interfaceExternalIds != null && !interfaceExternalIds.isEmpty()) {
295             Set<String> externalIdKeys = interfaceExternalIds.keySet();
296             List<InterfaceExternalIds> externalIdsList =
297                     new ArrayList<InterfaceExternalIds>();
298             String externalIdValue;
299             for (String externalIdKey : externalIdKeys) {
300                 externalIdValue = interfaceExternalIds.get(externalIdKey);
301                 if (externalIdKey != null && externalIdValue != null) {
302                     externalIdsList.add(new InterfaceExternalIdsBuilder()
303                             .setExternalIdKey(externalIdKey)
304                             .setExternalIdValue(externalIdValue).build());
305                 }
306             }
307             ovsdbTerminationPointBuilder.setInterfaceExternalIds(externalIdsList);
308         }
309     }
310
311     private void updatePortExternalIds(final Port port,
312             final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
313
314         Map<String, String> portExternalIds = port.getExternalIdsColumn().getData();
315         if (portExternalIds != null && !portExternalIds.isEmpty()) {
316             Set<String> externalIdKeys = portExternalIds.keySet();
317             List<PortExternalIds> externalIdsList = new ArrayList<PortExternalIds>();
318             String externalIdValue;
319             for (String externalIdKey : externalIdKeys) {
320                 externalIdValue = portExternalIds.get(externalIdKey);
321                 if (externalIdKey != null && externalIdValue != null) {
322                     externalIdsList.add(new PortExternalIdsBuilder()
323                             .setExternalIdKey(externalIdKey)
324                             .setExternalIdValue(externalIdValue).build());
325                 }
326             }
327             ovsdbTerminationPointBuilder.setPortExternalIds(externalIdsList);
328         }
329     }
330
331     private void updateOptions(final Interface interf,
332             final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
333
334         Map<String, String> optionsMap = interf.getOptionsColumn().getData();
335         if (optionsMap != null && !optionsMap.isEmpty()) {
336             List<Options> options = new ArrayList<Options>();
337             String optionsValueString;
338             OptionsKey optionsKey;
339             for (String optionsKeyString : optionsMap.keySet()) {
340                 optionsValueString = optionsMap.get(optionsKeyString);
341                 if (optionsKeyString != null && optionsValueString != null) {
342                     optionsKey = new OptionsKey(optionsKeyString);
343                     options.add(new OptionsBuilder()
344                         .setKey(optionsKey)
345                         .setValue(optionsValueString).build());
346                 }
347             }
348             ovsdbTerminationPointBuilder.setOptions(options);
349         }
350     }
351
352     private void updatePortOtherConfig(final Port port,
353             final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
354
355         Map<String, String> portOtherConfigMap = port.getOtherConfigColumn().getData();
356         if (portOtherConfigMap != null && !portOtherConfigMap.isEmpty()) {
357             List<PortOtherConfigs> portOtherConfigs = new ArrayList<PortOtherConfigs>();
358             String portOtherConfigValueString;
359             for (String portOtherConfigKeyString : portOtherConfigMap.keySet()) {
360                 portOtherConfigValueString = portOtherConfigMap.get(portOtherConfigKeyString);
361                 if (portOtherConfigKeyString != null && portOtherConfigValueString != null) {
362                     portOtherConfigs.add(new PortOtherConfigsBuilder()
363                         .setOtherConfigKey(portOtherConfigKeyString)
364                         .setOtherConfigValue(portOtherConfigValueString).build());
365                 }
366             }
367             ovsdbTerminationPointBuilder.setPortOtherConfigs(portOtherConfigs);
368         }
369     }
370
371     private void updateInterfaceOtherConfig(final Interface interf,
372             final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
373
374         Map<String, String> interfaceOtherConfigMap = interf.getOtherConfigColumn().getData();
375         if (interfaceOtherConfigMap != null && !interfaceOtherConfigMap.isEmpty()) {
376             List<InterfaceOtherConfigs> interfaceOtherConfigs = new ArrayList<InterfaceOtherConfigs>();
377             String interfaceOtherConfigValueString;
378             for (String interfaceOtherConfigKeyString : interfaceOtherConfigMap.keySet()) {
379                 interfaceOtherConfigValueString = interfaceOtherConfigMap.get(interfaceOtherConfigKeyString);
380                 if (interfaceOtherConfigKeyString != null && interfaceOtherConfigValueString != null) {
381                     interfaceOtherConfigs.add(new InterfaceOtherConfigsBuilder()
382                         .setOtherConfigKey(interfaceOtherConfigKeyString)
383                         .setOtherConfigValue(interfaceOtherConfigValueString).build());
384                 }
385             }
386             ovsdbTerminationPointBuilder.setInterfaceOtherConfigs(interfaceOtherConfigs);
387         }
388     }
389 }