2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.groupbasedpolicy.neutron.ovsdb.util;
10 import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.getOvsdbBridgeFromTerminationPoint;
11 import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.getOvsdbTerminationPoint;
12 import static org.opendaylight.groupbasedpolicy.util.DataStoreHelper.readFromDs;
13 import static org.opendaylight.groupbasedpolicy.util.DataStoreHelper.submitToDs;
15 import com.google.common.base.Optional;
16 import java.util.ArrayList;
17 import java.util.HashSet;
18 import java.util.List;
20 import org.apache.commons.lang3.StringUtils;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
23 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.groupbasedpolicy.neutron.ovsdb.AbstractTunnelType;
26 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfig;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfigBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.ExternalInterfaces;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.ExternalInterfacesBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.ExternalInterfacesKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.Tunnel;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.TunnelBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
47 public final class InventoryHelper {
49 private static final Logger LOG = LoggerFactory.getLogger(InventoryHelper.class);
50 private static final String HEX = "0x";
52 private InventoryHelper() {
56 * Convert an OpenFlow Datapath ID to a Long.
58 * @param dpid The OpenFlow Datapath ID
59 * @return The Long representation of the DPID
61 public static Long getLongFromDpid(String dpid) {
62 String[] addressInBytes = dpid.split(":");
63 Long address = Long.decode(HEX + addressInBytes[2]) << 40 | Long.decode(HEX + addressInBytes[3]) << 32
64 | Long.decode(HEX + addressInBytes[4]) << 24 | Long.decode(HEX + addressInBytes[5]) << 16
65 | Long.decode(HEX + addressInBytes[6]) << 8 | Long.decode(HEX + addressInBytes[7]);
69 private static final Long MAX_OF_PORT = 65534L;
72 * Construct a String that can be used to create a {@link NodeId}.
73 * The String is constructed by getting the Datapath ID from the OVSDB bridge
74 * augmentation, converting that to a Long, and prepending it with the
77 * @param ovsdbBridge The {@link OvsdbBridgeAugmentation}
78 * @param ovsdbTpIid the {@link OvsdbTerminationPointAugmentation}
79 * @param dataBroker the {@link DataBroker}
80 * @return String representation of the Inventory NodeId, null if it fails
82 public static String getInventoryNodeIdString(OvsdbBridgeAugmentation ovsdbBridge,
83 InstanceIdentifier<OvsdbTerminationPointAugmentation> ovsdbTpIid, DataBroker dataBroker) {
84 DatapathId dpid = ovsdbBridge.getDatapathId();
86 OvsdbBridgeAugmentation bridgeData = getOvsdbBridgeFromTerminationPoint(ovsdbTpIid, dataBroker);
87 dpid = bridgeData.getDatapathId();
89 LOG.error("No Data Path ID for OVSDB Bridge {}", ovsdbBridge);
93 Long macLong = getLongFromDpid(ovsdbBridge.getDatapathId().getValue());
94 String nodeIdString = "openflow:" + String.valueOf(macLong);
95 if (StringUtils.countMatches(nodeIdString, ":") != 1) {
96 LOG.error("{} is not correct format for NodeId.", nodeIdString);
103 * Construct a string that can be used to create a
104 * {@link org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId}.
105 * The String is constructed by first getting the inventory Node ID string, and then
106 * adding the port number obtained by the OVSDB augmentation.
108 * @param inventoryNodeId The string representation of the Inventory NodeId
109 * @param ovsdbTp The {@link OvsdbTerminationPointAugmentation}
110 * @param tpIid the InstanceIdentifier for OvsdbTerminationPointAugmentation
111 * @param dataBroker the {@link DataBroker}
112 * @return String representation of the Inventory NodeConnectorId, null if it fails
114 public static String getInventoryNodeConnectorIdString(String inventoryNodeId,
115 OvsdbTerminationPointAugmentation ovsdbTp, InstanceIdentifier<OvsdbTerminationPointAugmentation> tpIid,
116 DataBroker dataBroker) {
118 if (ovsdbTp.getOfport() != null && ovsdbTp.getOfport() > MAX_OF_PORT) {
119 LOG.debug("Invalid OpenFlow port {} for {}", ovsdbTp.getOfport(), ovsdbTp);
122 if (ovsdbTp.getOfport() == null) {
123 OvsdbTerminationPointAugmentation readOvsdbTp = getOvsdbTerminationPoint(tpIid, dataBroker);
124 if (readOvsdbTp == null || readOvsdbTp.getOfport() == null || readOvsdbTp.getOfport() > MAX_OF_PORT) {
125 LOG.debug("Couldn't get OpenFlow port for {}", ovsdbTp);
128 ofport = readOvsdbTp.getOfport();
130 ofport = ovsdbTp.getOfport();
132 String nodeConnectorIdString = inventoryNodeId + ":" + String.valueOf(ofport);
134 if (StringUtils.countMatches(nodeConnectorIdString, ":") != 2) {
135 LOG.error("{} is not correct format for NodeConnectorId.", nodeConnectorIdString);
138 return nodeConnectorIdString;
142 * Read the {@link OfOverlayNodeConfig} augmentation from the
143 * Inventory Node, and verify that the tunnel types we need
146 * @param nodeIdString The inventory node id string
147 * @param requiredTunnelTypes the list of tunnel types
148 * @param dataBroker the {@link DataBroker}
149 * @return true if tunnel types are present, false otherwise
151 public static boolean checkOfOverlayConfig(String nodeIdString, List<AbstractTunnelType> requiredTunnelTypes,
152 DataBroker dataBroker) {
153 OfOverlayNodeConfig config = getOfOverlayConfig(nodeIdString, dataBroker);
154 if (config == null || config.getTunnel() == null) {
155 LOG.debug("No OfOverlay config for {}", nodeIdString);
160 * See if the OfOverlayNodeConfig has the
161 * tunnel type information.
163 for (AbstractTunnelType tunnelType : requiredTunnelTypes) {
164 boolean tunnelPresent = false;
165 for (Tunnel tunnel : config.getTunnel()) {
166 if (tunnelType.getTunnelType().equals(tunnel.getTunnelType())) {
167 tunnelPresent = true;
171 if (tunnelPresent == false) {
178 public static InstanceIdentifier<ExternalInterfaces> addOfOverlayExternalPort(NodeId nodeId, NodeConnectorId ncId,
179 DataBroker dataBroker) {
180 InstanceIdentifier<ExternalInterfaces> nodeExternalInterfacesIid = InstanceIdentifier.builder(Nodes.class)
181 .child(Node.class, new NodeKey(nodeId))
182 .augmentation(OfOverlayNodeConfig.class)
183 .child(ExternalInterfaces.class, new ExternalInterfacesKey(ncId))
186 ExternalInterfaces externalInterfaces = new ExternalInterfacesBuilder().setKey(new ExternalInterfacesKey(ncId))
187 .setNodeConnectorId(ncId)
189 WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
190 transaction.put(LogicalDatastoreType.CONFIGURATION, nodeExternalInterfacesIid, externalInterfaces, true);
191 DataStoreHelper.submitToDs(transaction);
192 LOG.trace("Added external interface node connector {} to node {}", ncId.getValue(), nodeId.getValue());
193 return nodeExternalInterfacesIid;
196 public static OfOverlayNodeConfig getOfOverlayConfig(String nodeIdString, DataBroker dataBroker) {
197 InstanceIdentifier<OfOverlayNodeConfig> ofOverlayNodeIid = InstanceIdentifier.builder(Nodes.class)
198 .child(Node.class, new NodeKey(new NodeId(nodeIdString)))
199 .augmentation(OfOverlayNodeConfig.class)
202 ReadWriteTransaction transaction = dataBroker.newReadWriteTransaction();
203 Optional<OfOverlayNodeConfig> overlayConfig = readFromDs(LogicalDatastoreType.CONFIGURATION, ofOverlayNodeIid,
205 if (overlayConfig.isPresent()) {
206 return overlayConfig.get();
212 * Update the {@link OfOverlayNodeConfig} of an Inventory Node
213 * using the new tunnel state.
215 * @param ip the ipaddress
216 * @param nodeIdString the string representation of the inventory NodeId
217 * @param nodeConnectorIdString the string representation of the inventory NodeConnectorId
218 * @param tunnelType the tunnel type
219 * @param dataBroker the {@link DataBroker}
221 public static void updateOfOverlayConfig(IpAddress ip, String nodeIdString, String nodeConnectorIdString,
222 AbstractTunnelType tunnelType, DataBroker dataBroker) {
224 if (ip == null || nodeIdString == null || nodeConnectorIdString == null) {
225 LOG.debug("Can't update OfOverlay: requisite information not present");
228 NodeConnectorId nodeConnectorId = new NodeConnectorId(nodeConnectorIdString);
231 // Pull existing augmentation
232 OfOverlayNodeConfig ofConfig = getOfOverlayConfig(nodeIdString, dataBroker);
234 // If it exists, use it in new augmentation constructor, else new augmentation
235 OfOverlayNodeConfigBuilder ofOverlayNodeConfigBuilder;
236 Set<Tunnel> existingTunnels = new HashSet<>();
237 if (ofConfig != null) {
238 ofOverlayNodeConfigBuilder = new OfOverlayNodeConfigBuilder(ofConfig);
239 if (ofConfig.getTunnel() != null) {
240 existingTunnels.addAll(ofConfig.getTunnel());
243 ofOverlayNodeConfigBuilder = new OfOverlayNodeConfigBuilder();
246 // Determine if this is an update to existing tunnel of this type or a new tunnel
247 boolean tunnelsUpdated = false;
248 TunnelBuilder tunnelBuilder = new TunnelBuilder();
250 boolean tunnelFound = false;
251 for (Tunnel currentTun : existingTunnels) {
252 if (tunnelType.getTunnelType().equals(currentTun.getTunnelType())) {
254 tunnelBuilder.setIp(ip);
255 tunnelBuilder.setPort(tunnelType.getPortNumber());
256 tunnelBuilder.setNodeConnectorId(nodeConnectorId);
257 tunnelBuilder.setTunnelType(tunnelType.getTunnelType());
259 tunnelsUpdated = true;
264 if (tunnelFound == false) {
265 tunnelBuilder.setIp(ip);
266 tunnelBuilder.setPort(tunnelType.getPortNumber());
267 tunnelBuilder.setNodeConnectorId(nodeConnectorId);
268 tunnelBuilder.setTunnelType(tunnelType.getTunnelType());
269 tunnelsUpdated = true;
272 // Nothing was updated, nothing to see here, move along...
273 if (tunnelsUpdated == false) {
277 existingTunnels.add(tunnelBuilder.build());
279 // Update the OfOverlayNodeConfig with the new tunnel information
280 if (!existingTunnels.isEmpty()) {
281 ofOverlayNodeConfigBuilder.setTunnel(new ArrayList<>(existingTunnels));
283 OfOverlayNodeConfig newConfig = ofOverlayNodeConfigBuilder.build();
284 if (addOfOverlayConfig(newConfig, new NodeId(nodeIdString), dataBroker)) {
285 LOG.trace("updateOfOverlayConfig - Added Tunnel: {} to Node: {} at NodeConnector: {}",
286 tunnelBuilder.build(), nodeIdString, nodeConnectorIdString);
288 LOG.error("updateOfOverlayConfig - could not write OfOverlayNodeConfig: {} to datastore.", newConfig);
292 public static void removeTunnelsOfOverlayConfig(String nodeIdString,
293 List<AbstractTunnelType> tunnels,
294 DataBroker dataBroker) {
296 if (nodeIdString == null) {
297 LOG.debug("Can't update OfOverlay: requisite information not present");
300 List<Tunnel> existingTunnels = new ArrayList<>();
301 OfOverlayNodeConfig ofConfig = getOfOverlayConfig(nodeIdString, dataBroker);
302 if (ofConfig != null) {
303 existingTunnels = ofConfig.getTunnel();
305 Set<Tunnel> tunnelsToRemove = new HashSet<>();
306 for (AbstractTunnelType tunnelType : tunnels) {
307 for (Tunnel currentTun : existingTunnels) {
308 if (tunnelType.getTunnelType().equals(currentTun.getTunnelType())) {
309 tunnelsToRemove.add(currentTun);
314 // runs only if some tunnels were really removed
315 if (existingTunnels.removeAll(tunnelsToRemove)) {
316 ReadWriteTransaction writeTx = dataBroker.newReadWriteTransaction();
317 for (Tunnel tunnel : tunnelsToRemove) {
318 InstanceIdentifier<Tunnel> tunnelIid = InstanceIdentifier.builder(Nodes.class)
319 .child(Node.class, new NodeKey(new NodeId(nodeIdString)))
320 .augmentation(OfOverlayNodeConfig.class)
321 .child(Tunnel.class, tunnel.getKey())
323 writeTx.delete(LogicalDatastoreType.CONFIGURATION, tunnelIid);
324 LOG.trace("Removing tunnel: {} from node {}",tunnel, nodeIdString);
330 private static boolean addOfOverlayConfig(OfOverlayNodeConfig newConfig, NodeId nodeId, DataBroker dataBroker) {
331 ReadWriteTransaction writeTx = dataBroker.newReadWriteTransaction();
332 InstanceIdentifier<OfOverlayNodeConfig> ofOverlayNodeIid = InstanceIdentifier.builder(Nodes.class)
333 .child(Node.class, new NodeKey(nodeId))
334 .augmentation(OfOverlayNodeConfig.class)
336 writeTx.put(LogicalDatastoreType.CONFIGURATION, ofOverlayNodeIid, newConfig, true);
337 LOG.trace("Adding tunnel: {} to node {}", newConfig, nodeId.getValue());
338 return submitToDs(writeTx);
341 private static boolean addTunnelsOfOverlayConfig(List<Tunnel> tunnels, NodeId nodeId, DataBroker dataBroker) {
342 ReadWriteTransaction writeTx = dataBroker.newReadWriteTransaction();
343 for (Tunnel tunnel : tunnels) {
344 InstanceIdentifier<Tunnel> tunnelIid = InstanceIdentifier.builder(Nodes.class)
345 .child(Node.class, new NodeKey(nodeId))
346 .augmentation(OfOverlayNodeConfig.class)
347 .child(Tunnel.class, tunnel.getKey())
349 writeTx.put(LogicalDatastoreType.CONFIGURATION, tunnelIid, tunnel, true);
350 LOG.trace("Adding tunnel: {} to node {}",tunnel, nodeId.getValue());
352 return submitToDs(writeTx);