Squashed commit of the following:
[ovsdb.git] / southbound / southbound-impl / src / main / java / org / opendaylight / ovsdb / southbound / transactions / md / OvsdbBridgeUpdateCommand.java
1 package org.opendaylight.ovsdb.southbound.transactions.md;
2
3 import java.net.InetAddress;
4 import java.net.NetworkInterface;
5 import java.util.ArrayList;
6 import java.util.Enumeration;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Map.Entry;
10 import java.util.Set;
11
12 import org.apache.commons.lang3.math.NumberUtils;
13 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
14 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
15 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
16 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
17 import org.opendaylight.ovsdb.lib.message.TableUpdates;
18 import org.opendaylight.ovsdb.lib.notation.UUID;
19 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
20 import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
21 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
22 import org.opendaylight.ovsdb.schema.openvswitch.Controller;
23 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
24 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentationBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeName;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolBase;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentationBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeRef;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeExternalIds;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeExternalIdsBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeExternalIdsKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigs;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigsBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigsKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntryKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagedNodeEntry;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagedNodeEntryBuilder;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
52 import org.opendaylight.yangtools.yang.binding.DataObject;
53 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 import com.google.common.base.Optional;
58 import com.google.common.base.Preconditions;
59 import com.google.common.net.InetAddresses;
60
61 public class OvsdbBridgeUpdateCommand extends AbstractTransactionCommand {
62     private static final Logger LOG = LoggerFactory.getLogger(OvsdbBridgeUpdateCommand.class);
63     private Map<UUID,Bridge> updatedBridgeRows;
64     private Map<UUID, Bridge> oldBridgeRows;
65
66     public OvsdbBridgeUpdateCommand(ConnectionInfo key, TableUpdates updates,
67             DatabaseSchema dbSchema) {
68         super(key,updates,dbSchema);
69         updatedBridgeRows = TyperUtils.extractRowsUpdated(Bridge.class, getUpdates(), getDbSchema());
70         oldBridgeRows = TyperUtils.extractRowsOld(Bridge.class, getUpdates(), getDbSchema());
71     }
72
73     @Override
74     public void execute(ReadWriteTransaction transaction) {
75         for (Entry<UUID, Bridge> entry : updatedBridgeRows.entrySet()) {
76             updateBridge(transaction, entry.getValue());
77         }
78     }
79
80     private void updateBridge(ReadWriteTransaction transaction,
81             Bridge bridge) {
82         final InstanceIdentifier<Node> connectionIId = SouthboundMapper.createInstanceIdentifier(getConnectionInfo());
83         Optional<Node> connection = readNode(transaction, connectionIId);
84         if (connection.isPresent()) {
85             LOG.debug("Connection {} is present",connection);
86
87             // Update the connection node to let it know it manages this bridge
88             Node connectionNode = buildConnectionNode(bridge);
89             transaction.merge(LogicalDatastoreType.OPERATIONAL, connectionIId, connectionNode);
90
91             // Update the bridge node with whatever data we are getting
92             InstanceIdentifier<Node> bridgeIid = SouthboundMapper.createInstanceIdentifier(getConnectionInfo(),bridge);
93             Node bridgeNode = buildBridgeNode(bridge);
94             transaction.merge(LogicalDatastoreType.OPERATIONAL, bridgeIid, bridgeNode);
95             deleteEntries(transaction, protocolEntriesToRemove(bridgeIid,bridge));
96             deleteEntries(transaction, externalIdsToRemove(bridgeIid,bridge));
97             deleteEntries(transaction, bridgeOtherConfigsToRemove(bridgeIid,bridge));
98         }
99     }
100
101     private <T extends DataObject> void deleteEntries(ReadWriteTransaction transaction,
102             List<InstanceIdentifier<T>> entryIids) {
103         for (InstanceIdentifier<T> entryIid: entryIids) {
104             transaction.delete(LogicalDatastoreType.OPERATIONAL, entryIid);
105         }
106     }
107
108     private List<InstanceIdentifier<BridgeOtherConfigs>> bridgeOtherConfigsToRemove(
109             InstanceIdentifier<Node> bridgeIid, Bridge bridge) {
110         Preconditions.checkNotNull(bridgeIid);
111         Preconditions.checkNotNull(bridge);
112         List<InstanceIdentifier<BridgeOtherConfigs>> result =
113                 new ArrayList<InstanceIdentifier<BridgeOtherConfigs>>();
114
115         Bridge oldBridge = oldBridgeRows.get(bridge.getUuid());
116
117         if (oldBridge != null && oldBridge.getOtherConfigColumn() != null) {
118             for (Entry<String, String> otherConfig:
119                 oldBridge.getOtherConfigColumn().getData().entrySet()) {
120                 if (bridge.getOtherConfigColumn() == null
121                         || !bridge.getOtherConfigColumn().getData().containsKey(otherConfig.getKey())) {
122                     InstanceIdentifier<BridgeOtherConfigs> iid = bridgeIid
123                             .augmentation(OvsdbBridgeAugmentation.class)
124                             .child(BridgeOtherConfigs.class,
125                                     new BridgeOtherConfigsKey(otherConfig.getKey()));
126                     result.add(iid);
127                 }
128             }
129         }
130         return result;
131     }
132
133     private List<InstanceIdentifier<BridgeExternalIds>> externalIdsToRemove(
134             InstanceIdentifier<Node> bridgeIid, Bridge bridge) {
135         Preconditions.checkNotNull(bridgeIid);
136         Preconditions.checkNotNull(bridge);
137         List<InstanceIdentifier<BridgeExternalIds>> result =
138                 new ArrayList<InstanceIdentifier<BridgeExternalIds>>();
139
140         Bridge oldBridge = oldBridgeRows.get(bridge.getUuid());
141
142         if (oldBridge != null && oldBridge.getExternalIdsColumn() != null) {
143             for (Entry<String, String> externalId:
144                 oldBridge.getExternalIdsColumn().getData().entrySet()) {
145                 if (bridge.getExternalIdsColumn() == null
146                         || !bridge.getExternalIdsColumn().getData().containsKey(externalId.getKey())) {
147                     InstanceIdentifier<BridgeExternalIds> iid = bridgeIid
148                             .augmentation(OvsdbBridgeAugmentation.class)
149                             .child(BridgeExternalIds.class,
150                                     new BridgeExternalIdsKey(externalId.getKey()));
151                     result.add(iid);
152                 }
153             }
154         }
155         return result;
156     }
157
158     private List<InstanceIdentifier<ProtocolEntry>> protocolEntriesToRemove(
159             InstanceIdentifier<Node> bridgeIid, Bridge bridge) {
160         Preconditions.checkNotNull(bridgeIid);
161         Preconditions.checkNotNull(bridge);
162         List<InstanceIdentifier<ProtocolEntry>> result =
163                 new ArrayList<InstanceIdentifier<ProtocolEntry>>();
164         Bridge oldBridge = oldBridgeRows.get(bridge.getUuid());
165
166         try {
167             if (oldBridge != null && oldBridge.getProtocolsColumn() != null) {
168                 for (String protocol : oldBridge.getProtocolsColumn().getData()) {
169                     if (bridge.getProtocolsColumn() == null || !bridge.getProtocolsColumn().getData()
170                                 .contains(protocol)) {
171                         Class<? extends OvsdbBridgeProtocolBase> proto = SouthboundConstants.OVSDB_PROTOCOL_MAP
172                                 .inverse().get(protocol);
173                         InstanceIdentifier<ProtocolEntry> iid = bridgeIid
174                                 .augmentation(OvsdbBridgeAugmentation.class)
175                                 .child(ProtocolEntry.class,
176                                         new ProtocolEntryKey(proto));
177                         result.add(iid);
178                     }
179                 }
180             }
181         } catch (SchemaVersionMismatchException e) {
182             LOG.warn("protocol not supported by this version of ovsdb", e);
183         }
184         return result;
185     }
186
187     private Optional<Node> readNode(ReadWriteTransaction transaction,
188             final InstanceIdentifier<Node> connectionIid) {
189         Optional<Node> node = Optional.absent();
190         try {
191             node = transaction.read(LogicalDatastoreType.OPERATIONAL, connectionIid).checkedGet();
192         } catch (final ReadFailedException e) {
193             LOG.warn("Read Operational/DS for Node fail! {}", connectionIid, e);
194         }
195         return node;
196     }
197
198     private Node buildConnectionNode(
199             Bridge bridge) {
200         //Update node with managed node reference
201         NodeBuilder connectionNode = new NodeBuilder();
202         connectionNode.setNodeId(SouthboundMapper.createNodeId(getConnectionInfo().getRemoteIp(),
203                 getConnectionInfo().getRemotePort()));
204
205         OvsdbNodeAugmentationBuilder ovsdbConnectionAugmentationBuilder = new OvsdbNodeAugmentationBuilder();
206         List<ManagedNodeEntry> managedBridges = new ArrayList<ManagedNodeEntry>();
207         InstanceIdentifier<Node> bridgeIid = SouthboundMapper.createInstanceIdentifier(getConnectionInfo(),bridge);
208         ManagedNodeEntry managedBridge = new ManagedNodeEntryBuilder().setBridgeRef(
209                 new OvsdbBridgeRef(bridgeIid)).build();
210         managedBridges.add(managedBridge);
211         ovsdbConnectionAugmentationBuilder.setManagedNodeEntry(managedBridges);
212
213         connectionNode.addAugmentation(OvsdbNodeAugmentation.class, ovsdbConnectionAugmentationBuilder.build());
214
215         LOG.debug("Update node with bridge node ref {}",ovsdbConnectionAugmentationBuilder.toString());
216         return connectionNode.build();
217     }
218
219     private Node buildBridgeNode(Bridge bridge) {
220         NodeBuilder bridgeNodeBuilder = new NodeBuilder();
221         InstanceIdentifier<Node> bridgeIid = SouthboundMapper.createInstanceIdentifier(getConnectionInfo(),bridge);
222         NodeId bridgeNodeId = SouthboundMapper.createManagedNodeId(bridgeIid);
223         bridgeNodeBuilder.setNodeId(bridgeNodeId);
224         OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder();
225         ovsdbBridgeAugmentationBuilder.setBridgeName(new OvsdbBridgeName(bridge.getName()));
226         ovsdbBridgeAugmentationBuilder.setBridgeUuid(new Uuid(bridge.getUuid().toString()));
227         setDataPath(ovsdbBridgeAugmentationBuilder, bridge);
228         setDataPathType(ovsdbBridgeAugmentationBuilder, bridge);
229         setProtocol(ovsdbBridgeAugmentationBuilder, bridge);
230         setExternalIds(ovsdbBridgeAugmentationBuilder, bridge);
231         setOtherConfig(ovsdbBridgeAugmentationBuilder, bridge);
232         setFailMode(ovsdbBridgeAugmentationBuilder, bridge);
233         setOpenFlowNodeRef(ovsdbBridgeAugmentationBuilder, bridge);
234         setManagedBy(ovsdbBridgeAugmentationBuilder);
235         bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, ovsdbBridgeAugmentationBuilder.build());
236
237         LOG.debug("Built with the intent to store bridge data {}",
238                 ovsdbBridgeAugmentationBuilder.toString());
239         return bridgeNodeBuilder.build();
240     }
241
242     private void setManagedBy(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder) {
243         InstanceIdentifier<Node> connectionNodePath = SouthboundMapper.createInstanceIdentifier(getConnectionInfo());
244         ovsdbBridgeAugmentationBuilder.setManagedBy(new OvsdbNodeRef(connectionNodePath));
245     }
246
247     private void setDataPathType(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
248             Bridge bridge) {
249         ovsdbBridgeAugmentationBuilder.setDatapathType(
250                 SouthboundMapper.createDatapathType(bridge.getDatapathTypeColumn().getData()));
251     }
252
253     private void setFailMode(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
254             Bridge bridge) {
255         if (bridge.getFailModeColumn() != null
256                 && bridge.getFailModeColumn().getData() != null
257                 && !bridge.getFailModeColumn().getData().isEmpty()) {
258             String[] failmodeArray = new String[bridge.getFailModeColumn().getData().size()];
259             bridge.getFailModeColumn().getData().toArray(failmodeArray);
260             ovsdbBridgeAugmentationBuilder.setFailMode(
261                     SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get(failmodeArray[0]));
262         }
263     }
264
265     private void setOtherConfig(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
266             Bridge bridge) {
267         Map<String, String> otherConfigs = bridge
268                 .getOtherConfigColumn().getData();
269         if (otherConfigs != null && !otherConfigs.isEmpty()) {
270             Set<String> otherConfigKeys = otherConfigs.keySet();
271             List<BridgeOtherConfigs> otherConfigList = new ArrayList<BridgeOtherConfigs>();
272             String otherConfigValue;
273             for (String otherConfigKey : otherConfigKeys) {
274                 otherConfigValue = otherConfigs.get(otherConfigKey);
275                 if (otherConfigKey != null && otherConfigValue != null) {
276                     otherConfigList.add(new BridgeOtherConfigsBuilder()
277                             .setBridgeOtherConfigKey(otherConfigKey)
278                             .setBridgeOtherConfigValue(otherConfigValue)
279                             .build());
280                 }
281             }
282             ovsdbBridgeAugmentationBuilder.setBridgeOtherConfigs(otherConfigList);
283         }
284     }
285
286     private void setExternalIds(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
287             Bridge bridge) {
288         Map<String, String> externalIds = bridge.getExternalIdsColumn()
289                 .getData();
290         if (externalIds != null && !externalIds.isEmpty()) {
291             Set<String> externalIdKeys = externalIds.keySet();
292             List<BridgeExternalIds> externalIdsList = new ArrayList<BridgeExternalIds>();
293             String externalIdValue;
294             for (String externalIdKey : externalIdKeys) {
295                 externalIdValue = externalIds.get(externalIdKey);
296                 if (externalIdKey != null && externalIdValue != null) {
297                     externalIdsList.add(new BridgeExternalIdsBuilder()
298                             .setBridgeExternalIdKey(externalIdKey)
299                             .setBridgeExternalIdValue(externalIdValue)
300                             .build());
301                 }
302             }
303             ovsdbBridgeAugmentationBuilder.setBridgeExternalIds(externalIdsList);
304         }
305     }
306
307     private void setProtocol(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
308             Bridge bridge) {
309         if (SouthboundMapper.createMdsalProtocols(bridge) != null
310                 && SouthboundMapper.createMdsalProtocols(bridge).size() > 0) {
311             ovsdbBridgeAugmentationBuilder.setProtocolEntry(SouthboundMapper.createMdsalProtocols(bridge));
312         }
313     }
314
315     private void setDataPath(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
316             Bridge bridge) {
317         DatapathId dpid = SouthboundMapper.createDatapathId(bridge);
318         if (dpid != null) {
319             ovsdbBridgeAugmentationBuilder.setDatapathId(dpid);
320         }
321     }
322
323     private void setOpenFlowNodeRef(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
324             Bridge bridge) {
325         Map<UUID, Controller> updatedControllerRows =
326                 TyperUtils.extractRowsUpdated(Controller.class, getUpdates(), getDbSchema());
327         LOG.debug("setOpenFlowNodeRef: updatedControllerRows: {}", updatedControllerRows);
328         for (ControllerEntry controllerEntry: SouthboundMapper.createControllerEntries(bridge, updatedControllerRows)) {
329             if (controllerEntry != null
330                 && controllerEntry.isIsConnected() != null && controllerEntry.isIsConnected()) {
331                 String [] controllerTarget = controllerEntry.getTarget().getValue().split(":");
332                 IpAddress bridgeControllerIpAddress = null;
333                 PortNumber bridgeControllerPortNumber = null;
334                 for (String targetElement : controllerTarget) {
335                     if (InetAddresses.isInetAddress(targetElement)) {
336                         bridgeControllerIpAddress = new IpAddress(targetElement.toCharArray());
337                         continue;
338                     }
339                     if (NumberUtils.isNumber(targetElement)) {
340                         bridgeControllerPortNumber = new PortNumber(
341                                 Integer.valueOf(String.valueOf(targetElement)));
342                         continue;
343                     }
344                 }
345                 try {
346                     Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
347                 networkInterfacesLoop:
348                     while (networkInterfaces.hasMoreElements()) {
349                         NetworkInterface networkInterface = networkInterfaces.nextElement();
350                         Enumeration<InetAddress> networkInterfaceAddresses = networkInterface.getInetAddresses();
351                         while (networkInterfaceAddresses.hasMoreElements()) {
352                             InetAddress networkInterfaceAddress = networkInterfaceAddresses.nextElement();
353                             if (bridgeControllerIpAddress.getIpv4Address().getValue()
354                                     .equals(networkInterfaceAddress.getHostAddress())) {
355                                 ovsdbBridgeAugmentationBuilder.setBridgeOpenflowNodeRef(
356                                         SouthboundMapper.createInstanceIdentifier(bridgeControllerIpAddress,
357                                                 bridgeControllerPortNumber));
358                                 break networkInterfacesLoop;
359                             }
360                         }
361                     }
362                 } catch (Exception e) {
363                     LOG.warn("Error getting local ip address {}", e);
364                 }
365             }
366         }
367     }
368 }